xref: /qemu/hw/intc/arm_gicv3_its.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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;
301bcb9076SPeter Maydell     ResettablePhases parent_phases;
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 */
its_feature_virtual(GICv3ITSState * s)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 
intid_in_lpi_range(uint32_t id)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 
valid_doorbell(uint32_t id)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 
baser_base_addr(uint64_t value,uint32_t page_sz)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 
table_entry_addr(GICv3ITSState * s,TableDesc * td,uint32_t idx,MemTxResult * res)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  */
get_cte(GICv3ITSState * s,uint16_t icid,CTEntry * cte)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  */
update_ite(GICv3ITSState * s,uint32_t eventid,const DTEntry * dte,const ITEntry * ite)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  */
get_ite(GICv3ITSState * s,uint32_t eventid,const DTEntry * dte,ITEntry * ite)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  */
get_dte(GICv3ITSState * s,uint32_t devid,DTEntry * dte)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 /*
318469cf23bSPeter Maydell  * Read the vPE Table entry at index @vpeid. On success (including
319469cf23bSPeter Maydell  * successfully determining that there is no valid entry for this index),
320469cf23bSPeter Maydell  * we return MEMTX_OK and populate the VTEntry struct accordingly.
321469cf23bSPeter Maydell  * If there is an error reading memory then we return the error code.
322469cf23bSPeter Maydell  */
get_vte(GICv3ITSState * s,uint32_t vpeid,VTEntry * vte)323469cf23bSPeter Maydell static MemTxResult get_vte(GICv3ITSState *s, uint32_t vpeid, VTEntry *vte)
324469cf23bSPeter Maydell {
325469cf23bSPeter Maydell     MemTxResult res = MEMTX_OK;
326469cf23bSPeter Maydell     AddressSpace *as = &s->gicv3->dma_as;
327469cf23bSPeter Maydell     uint64_t entry_addr = table_entry_addr(s, &s->vpet, vpeid, &res);
328469cf23bSPeter Maydell     uint64_t vteval;
329469cf23bSPeter Maydell 
330469cf23bSPeter Maydell     if (entry_addr == -1) {
331469cf23bSPeter Maydell         /* No L2 table entry, i.e. no valid VTE, or a memory error */
332469cf23bSPeter Maydell         vte->valid = false;
3330df11497SPhilippe Mathieu-Daudé         trace_gicv3_its_vte_read_fault(vpeid);
3340df11497SPhilippe Mathieu-Daudé         return MEMTX_OK;
335469cf23bSPeter Maydell     }
336469cf23bSPeter Maydell     vteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res);
337469cf23bSPeter Maydell     if (res != MEMTX_OK) {
3380df11497SPhilippe Mathieu-Daudé         trace_gicv3_its_vte_read_fault(vpeid);
3390df11497SPhilippe Mathieu-Daudé         return res;
340469cf23bSPeter Maydell     }
341469cf23bSPeter Maydell     vte->valid = FIELD_EX64(vteval, VTE, VALID);
342469cf23bSPeter Maydell     vte->vptsize = FIELD_EX64(vteval, VTE, VPTSIZE);
343469cf23bSPeter Maydell     vte->vptaddr = FIELD_EX64(vteval, VTE, VPTADDR);
344469cf23bSPeter Maydell     vte->rdbase = FIELD_EX64(vteval, VTE, RDBASE);
345469cf23bSPeter Maydell     trace_gicv3_its_vte_read(vpeid, vte->valid, vte->vptsize,
346469cf23bSPeter Maydell                              vte->vptaddr, vte->rdbase);
347469cf23bSPeter Maydell     return res;
348469cf23bSPeter Maydell }
349469cf23bSPeter Maydell 
350469cf23bSPeter Maydell /*
351f0175135SPeter Maydell  * Given a (DeviceID, EventID), look up the corresponding ITE, including
352f0175135SPeter Maydell  * checking for the various invalid-value cases. If we find a valid ITE,
353f0175135SPeter Maydell  * fill in @ite and @dte and return CMD_CONTINUE_OK. Otherwise return
354f0175135SPeter Maydell  * CMD_STALL or CMD_CONTINUE as appropriate (and the contents of @ite
355f0175135SPeter Maydell  * should not be relied on).
356f0175135SPeter Maydell  *
357f0175135SPeter Maydell  * The string @who is purely for the LOG_GUEST_ERROR messages,
358f0175135SPeter Maydell  * and should indicate the name of the calling function or similar.
359f0175135SPeter Maydell  */
lookup_ite(GICv3ITSState * s,const char * who,uint32_t devid,uint32_t eventid,ITEntry * ite,DTEntry * dte)360f0175135SPeter Maydell static ItsCmdResult lookup_ite(GICv3ITSState *s, const char *who,
361f0175135SPeter Maydell                                uint32_t devid, uint32_t eventid, ITEntry *ite,
362f0175135SPeter Maydell                                DTEntry *dte)
363f0175135SPeter Maydell {
364f0175135SPeter Maydell     uint64_t num_eventids;
365f0175135SPeter Maydell 
366f0175135SPeter Maydell     if (devid >= s->dt.num_entries) {
367f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
368f0175135SPeter Maydell                       "%s: invalid command attributes: devid %d>=%d",
369f0175135SPeter Maydell                       who, devid, s->dt.num_entries);
370f0175135SPeter Maydell         return CMD_CONTINUE;
371f0175135SPeter Maydell     }
372f0175135SPeter Maydell 
373f0175135SPeter Maydell     if (get_dte(s, devid, dte) != MEMTX_OK) {
374f0175135SPeter Maydell         return CMD_STALL;
375f0175135SPeter Maydell     }
376f0175135SPeter Maydell     if (!dte->valid) {
377f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
378f0175135SPeter Maydell                       "%s: invalid command attributes: "
379f0175135SPeter Maydell                       "invalid dte for %d\n", who, devid);
380f0175135SPeter Maydell         return CMD_CONTINUE;
381f0175135SPeter Maydell     }
382f0175135SPeter Maydell 
383f0175135SPeter Maydell     num_eventids = 1ULL << (dte->size + 1);
384f0175135SPeter Maydell     if (eventid >= num_eventids) {
385f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
386f0175135SPeter Maydell                       "%s: invalid command attributes: eventid %d >= %"
387f0175135SPeter Maydell                       PRId64 "\n", who, eventid, num_eventids);
388f0175135SPeter Maydell         return CMD_CONTINUE;
389f0175135SPeter Maydell     }
390f0175135SPeter Maydell 
391f0175135SPeter Maydell     if (get_ite(s, eventid, dte, ite) != MEMTX_OK) {
392f0175135SPeter Maydell         return CMD_STALL;
393f0175135SPeter Maydell     }
394f0175135SPeter Maydell 
395f0175135SPeter Maydell     if (!ite->valid) {
396f0175135SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
397f0175135SPeter Maydell                       "%s: invalid command attributes: invalid ITE\n", who);
398f0175135SPeter Maydell         return CMD_CONTINUE;
399f0175135SPeter Maydell     }
400f0175135SPeter Maydell 
401f0175135SPeter Maydell     return CMD_CONTINUE_OK;
402f0175135SPeter Maydell }
403f0175135SPeter Maydell 
404f0175135SPeter Maydell /*
405c411db7bSPeter Maydell  * Given an ICID, look up the corresponding CTE, including checking for various
406c411db7bSPeter Maydell  * invalid-value cases. If we find a valid CTE, fill in @cte and return
407c411db7bSPeter Maydell  * CMD_CONTINUE_OK; otherwise return CMD_STALL or CMD_CONTINUE (and the
408c411db7bSPeter Maydell  * contents of @cte should not be relied on).
409c411db7bSPeter Maydell  *
410c411db7bSPeter Maydell  * The string @who is purely for the LOG_GUEST_ERROR messages,
411c411db7bSPeter Maydell  * and should indicate the name of the calling function or similar.
412c411db7bSPeter Maydell  */
lookup_cte(GICv3ITSState * s,const char * who,uint32_t icid,CTEntry * cte)413c411db7bSPeter Maydell static ItsCmdResult lookup_cte(GICv3ITSState *s, const char *who,
414c411db7bSPeter Maydell                                uint32_t icid, CTEntry *cte)
415c411db7bSPeter Maydell {
416c411db7bSPeter Maydell     if (icid >= s->ct.num_entries) {
417c411db7bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid ICID 0x%x\n", who, icid);
418c411db7bSPeter Maydell         return CMD_CONTINUE;
419c411db7bSPeter Maydell     }
420c411db7bSPeter Maydell     if (get_cte(s, icid, cte) != MEMTX_OK) {
421c411db7bSPeter Maydell         return CMD_STALL;
422c411db7bSPeter Maydell     }
423c411db7bSPeter Maydell     if (!cte->valid) {
424c411db7bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid CTE\n", who);
425c411db7bSPeter Maydell         return CMD_CONTINUE;
426c411db7bSPeter Maydell     }
427c411db7bSPeter Maydell     if (cte->rdbase >= s->gicv3->num_cpu) {
428c411db7bSPeter Maydell         return CMD_CONTINUE;
429c411db7bSPeter Maydell     }
430c411db7bSPeter Maydell     return CMD_CONTINUE_OK;
431c411db7bSPeter Maydell }
432c411db7bSPeter Maydell 
433469cf23bSPeter Maydell /*
434469cf23bSPeter Maydell  * Given a VPEID, look up the corresponding VTE, including checking
435469cf23bSPeter Maydell  * for various invalid-value cases. if we find a valid VTE, fill in @vte
436469cf23bSPeter Maydell  * and return CMD_CONTINUE_OK; otherwise return CMD_STALL or CMD_CONTINUE
437469cf23bSPeter Maydell  * (and the contents of @vte should not be relied on).
438469cf23bSPeter Maydell  *
439469cf23bSPeter Maydell  * The string @who is purely for the LOG_GUEST_ERROR messages,
440469cf23bSPeter Maydell  * and should indicate the name of the calling function or similar.
441469cf23bSPeter Maydell  */
lookup_vte(GICv3ITSState * s,const char * who,uint32_t vpeid,VTEntry * vte)442469cf23bSPeter Maydell static ItsCmdResult lookup_vte(GICv3ITSState *s, const char *who,
443469cf23bSPeter Maydell                                uint32_t vpeid, VTEntry *vte)
444469cf23bSPeter Maydell {
445469cf23bSPeter Maydell     if (vpeid >= s->vpet.num_entries) {
446469cf23bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid VPEID 0x%x\n", who, vpeid);
447469cf23bSPeter Maydell         return CMD_CONTINUE;
448469cf23bSPeter Maydell     }
449469cf23bSPeter Maydell 
450469cf23bSPeter Maydell     if (get_vte(s, vpeid, vte) != MEMTX_OK) {
451469cf23bSPeter Maydell         return CMD_STALL;
452469cf23bSPeter Maydell     }
453469cf23bSPeter Maydell     if (!vte->valid) {
454469cf23bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
455469cf23bSPeter Maydell                       "%s: invalid VTE for VPEID 0x%x\n", who, vpeid);
456469cf23bSPeter Maydell         return CMD_CONTINUE;
457469cf23bSPeter Maydell     }
458469cf23bSPeter Maydell 
459469cf23bSPeter Maydell     if (vte->rdbase >= s->gicv3->num_cpu) {
460469cf23bSPeter Maydell         return CMD_CONTINUE;
461469cf23bSPeter Maydell     }
462469cf23bSPeter Maydell     return CMD_CONTINUE_OK;
463469cf23bSPeter Maydell }
464469cf23bSPeter Maydell 
process_its_cmd_phys(GICv3ITSState * s,const ITEntry * ite,int irqlevel)4652d692e2bSPeter Maydell static ItsCmdResult process_its_cmd_phys(GICv3ITSState *s, const ITEntry *ite,
4662d692e2bSPeter Maydell                                          int irqlevel)
4672d692e2bSPeter Maydell {
4689678b9c5SPeter Maydell     CTEntry cte = {};
4692d692e2bSPeter Maydell     ItsCmdResult cmdres;
4702d692e2bSPeter Maydell 
4712d692e2bSPeter Maydell     cmdres = lookup_cte(s, __func__, ite->icid, &cte);
4722d692e2bSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
4732d692e2bSPeter Maydell         return cmdres;
4742d692e2bSPeter Maydell     }
4752d692e2bSPeter Maydell     gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite->intid, irqlevel);
4762d692e2bSPeter Maydell     return CMD_CONTINUE_OK;
4772d692e2bSPeter Maydell }
478c411db7bSPeter Maydell 
process_its_cmd_virt(GICv3ITSState * s,const ITEntry * ite,int irqlevel)479469cf23bSPeter Maydell static ItsCmdResult process_its_cmd_virt(GICv3ITSState *s, const ITEntry *ite,
480469cf23bSPeter Maydell                                          int irqlevel)
481469cf23bSPeter Maydell {
4829678b9c5SPeter Maydell     VTEntry vte = {};
483469cf23bSPeter Maydell     ItsCmdResult cmdres;
484469cf23bSPeter Maydell 
485469cf23bSPeter Maydell     cmdres = lookup_vte(s, __func__, ite->vpeid, &vte);
486469cf23bSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
487469cf23bSPeter Maydell         return cmdres;
488469cf23bSPeter Maydell     }
489469cf23bSPeter Maydell 
490469cf23bSPeter Maydell     if (!intid_in_lpi_range(ite->intid) ||
491469cf23bSPeter Maydell         ite->intid >= (1ULL << (vte.vptsize + 1))) {
492469cf23bSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "%s: intid 0x%x out of range\n",
493469cf23bSPeter Maydell                       __func__, ite->intid);
494469cf23bSPeter Maydell         return CMD_CONTINUE;
495469cf23bSPeter Maydell     }
496469cf23bSPeter Maydell 
497469cf23bSPeter Maydell     /*
498469cf23bSPeter Maydell      * For QEMU the actual pending of the vLPI is handled in the
499469cf23bSPeter Maydell      * redistributor code
500469cf23bSPeter Maydell      */
501469cf23bSPeter Maydell     gicv3_redist_process_vlpi(&s->gicv3->cpu[vte.rdbase], ite->intid,
502469cf23bSPeter Maydell                               vte.vptaddr << 16, ite->doorbell, irqlevel);
503469cf23bSPeter Maydell     return CMD_CONTINUE_OK;
504469cf23bSPeter Maydell }
505469cf23bSPeter Maydell 
506c411db7bSPeter Maydell /*
507c694cb4cSShashi Mallela  * This function handles the processing of following commands based on
508c694cb4cSShashi Mallela  * the ItsCmdType parameter passed:-
509c694cb4cSShashi Mallela  * 1. triggering of lpi interrupt translation via ITS INT command
510c694cb4cSShashi Mallela  * 2. triggering of lpi interrupt translation via gits_translater register
511c694cb4cSShashi Mallela  * 3. handling of ITS CLEAR command
512c694cb4cSShashi Mallela  * 4. handling of ITS DISCARD command
513c694cb4cSShashi Mallela  */
do_process_its_cmd(GICv3ITSState * s,uint32_t devid,uint32_t eventid,ItsCmdType cmd)514b6f96009SPeter Maydell static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
515b6f96009SPeter Maydell                                        uint32_t eventid, ItsCmdType cmd)
516c694cb4cSShashi Mallela {
5179678b9c5SPeter Maydell     DTEntry dte = {};
5189678b9c5SPeter Maydell     ITEntry ite = {};
519f0175135SPeter Maydell     ItsCmdResult cmdres;
5202d692e2bSPeter Maydell     int irqlevel;
521c694cb4cSShashi Mallela 
522f0175135SPeter Maydell     cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte);
523f0175135SPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
524f0175135SPeter Maydell         return cmdres;
525b13148d9SPeter Maydell     }
526b13148d9SPeter Maydell 
5272d692e2bSPeter Maydell     irqlevel = (cmd == CLEAR || cmd == DISCARD) ? 0 : 1;
5282d692e2bSPeter Maydell 
5292d692e2bSPeter Maydell     switch (ite.inttype) {
5302d692e2bSPeter Maydell     case ITE_INTTYPE_PHYSICAL:
5312d692e2bSPeter Maydell         cmdres = process_its_cmd_phys(s, &ite, irqlevel);
5322d692e2bSPeter Maydell         break;
5332d692e2bSPeter Maydell     case ITE_INTTYPE_VIRTUAL:
5342d692e2bSPeter Maydell         if (!its_feature_virtual(s)) {
5352d692e2bSPeter Maydell             /* Can't happen unless guest is illegally writing to table memory */
536be0ed8fbSPeter Maydell             qemu_log_mask(LOG_GUEST_ERROR,
5372d692e2bSPeter Maydell                           "%s: invalid type %d in ITE (table corrupted?)\n",
5382d692e2bSPeter Maydell                           __func__, ite.inttype);
539be0ed8fbSPeter Maydell             return CMD_CONTINUE;
540be0ed8fbSPeter Maydell         }
541469cf23bSPeter Maydell         cmdres = process_its_cmd_virt(s, &ite, irqlevel);
542469cf23bSPeter Maydell         break;
5432d692e2bSPeter Maydell     default:
5442d692e2bSPeter Maydell         g_assert_not_reached();
54517fb5e36SShashi Mallela     }
54617fb5e36SShashi Mallela 
5472d692e2bSPeter Maydell     if (cmdres == CMD_CONTINUE_OK && cmd == DISCARD) {
54833b3b4adSPeter Maydell         ITEntry i = {};
549c694cb4cSShashi Mallela         /* remove mapping from interrupt translation table */
55033b3b4adSPeter Maydell         i.valid = false;
55133b3b4adSPeter Maydell         return update_ite(s, eventid, &dte, &i) ? CMD_CONTINUE_OK : CMD_STALL;
552c694cb4cSShashi Mallela     }
55393f4fdcdSPeter Maydell     return CMD_CONTINUE_OK;
554c694cb4cSShashi Mallela }
5552a199036SPeter Maydell 
process_its_cmd(GICv3ITSState * s,const uint64_t * cmdpkt,ItsCmdType cmd)556b6f96009SPeter Maydell static ItsCmdResult process_its_cmd(GICv3ITSState *s, const uint64_t *cmdpkt,
557b6f96009SPeter Maydell                                     ItsCmdType cmd)
558c694cb4cSShashi Mallela {
559b6f96009SPeter Maydell     uint32_t devid, eventid;
560b6f96009SPeter Maydell 
561b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
562b6f96009SPeter Maydell     eventid = cmdpkt[1] & EVENTID_MASK;
563e4050980SPeter Maydell     switch (cmd) {
564e4050980SPeter Maydell     case INTERRUPT:
565e4050980SPeter Maydell         trace_gicv3_its_cmd_int(devid, eventid);
566e4050980SPeter Maydell         break;
567e4050980SPeter Maydell     case CLEAR:
568e4050980SPeter Maydell         trace_gicv3_its_cmd_clear(devid, eventid);
569e4050980SPeter Maydell         break;
570e4050980SPeter Maydell     case DISCARD:
571e4050980SPeter Maydell         trace_gicv3_its_cmd_discard(devid, eventid);
572e4050980SPeter Maydell         break;
573e4050980SPeter Maydell     default:
574e4050980SPeter Maydell         g_assert_not_reached();
575e4050980SPeter Maydell     }
576b6f96009SPeter Maydell     return do_process_its_cmd(s, devid, eventid, cmd);
577b6f96009SPeter Maydell }
578b6f96009SPeter Maydell 
process_mapti(GICv3ITSState * s,const uint64_t * cmdpkt,bool ignore_pInt)579b6f96009SPeter Maydell static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
580b6f96009SPeter Maydell                                   bool ignore_pInt)
581b6f96009SPeter Maydell {
582c694cb4cSShashi Mallela     uint32_t devid, eventid;
583c694cb4cSShashi Mallela     uint32_t pIntid = 0;
5848f809f69SPeter Maydell     uint64_t num_eventids;
585c694cb4cSShashi Mallela     uint16_t icid = 0;
5869678b9c5SPeter Maydell     DTEntry dte = {};
5879678b9c5SPeter Maydell     ITEntry ite = {};
588c694cb4cSShashi Mallela 
589b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
590b6f96009SPeter Maydell     eventid = cmdpkt[1] & EVENTID_MASK;
591e4050980SPeter Maydell     icid = cmdpkt[2] & ICID_MASK;
592c694cb4cSShashi Mallela 
593b87fab1cSPeter Maydell     if (ignore_pInt) {
594b87fab1cSPeter Maydell         pIntid = eventid;
595e4050980SPeter Maydell         trace_gicv3_its_cmd_mapi(devid, eventid, icid);
596b87fab1cSPeter Maydell     } else {
597b6f96009SPeter Maydell         pIntid = (cmdpkt[1] & pINTID_MASK) >> pINTID_SHIFT;
598e4050980SPeter Maydell         trace_gicv3_its_cmd_mapti(devid, eventid, icid, pIntid);
599c694cb4cSShashi Mallela     }
600c694cb4cSShashi Mallela 
6018b8bb014SPeter Maydell     if (devid >= s->dt.num_entries) {
602b13148d9SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
603b13148d9SPeter Maydell                       "%s: invalid command attributes: devid %d>=%d",
6048b8bb014SPeter Maydell                       __func__, devid, s->dt.num_entries);
605b13148d9SPeter Maydell         return CMD_CONTINUE;
606b13148d9SPeter Maydell     }
607b13148d9SPeter Maydell 
6084acf93e1SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
6090241f731SPeter Maydell         return CMD_STALL;
610c694cb4cSShashi Mallela     }
6114acf93e1SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
612c694cb4cSShashi Mallela 
613d7d359c4SPeter Maydell     if (icid >= s->ct.num_entries) {
614c694cb4cSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
615d7d359c4SPeter Maydell                       "%s: invalid ICID 0x%x >= 0x%x\n",
616d7d359c4SPeter Maydell                       __func__, icid, s->ct.num_entries);
617d7d359c4SPeter Maydell         return CMD_CONTINUE;
618d7d359c4SPeter Maydell     }
619d7d359c4SPeter Maydell 
620d7d359c4SPeter Maydell     if (!dte.valid) {
621d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
622d7d359c4SPeter Maydell                       "%s: no valid DTE for devid 0x%x\n", __func__, devid);
623d7d359c4SPeter Maydell         return CMD_CONTINUE;
624d7d359c4SPeter Maydell     }
625d7d359c4SPeter Maydell 
626d7d359c4SPeter Maydell     if (eventid >= num_eventids) {
627d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
628d7d359c4SPeter Maydell                       "%s: invalid event ID 0x%x >= 0x%" PRIx64 "\n",
629d7d359c4SPeter Maydell                       __func__, eventid, num_eventids);
630d7d359c4SPeter Maydell         return CMD_CONTINUE;
631d7d359c4SPeter Maydell     }
632d7d359c4SPeter Maydell 
633c3c9a090SPeter Maydell     if (!intid_in_lpi_range(pIntid)) {
634d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
635d7d359c4SPeter Maydell                       "%s: invalid interrupt ID 0x%x\n", __func__, pIntid);
6360241f731SPeter Maydell         return CMD_CONTINUE;
6370241f731SPeter Maydell     }
6380241f731SPeter Maydell 
639c694cb4cSShashi Mallela     /* add ite entry to interrupt translation table */
6407eb54267SPeter Maydell     ite.valid = true;
6417eb54267SPeter Maydell     ite.inttype = ITE_INTTYPE_PHYSICAL;
6427eb54267SPeter Maydell     ite.intid = pIntid;
6437eb54267SPeter Maydell     ite.icid = icid;
6447eb54267SPeter Maydell     ite.doorbell = INTID_SPURIOUS;
6457eb54267SPeter Maydell     ite.vpeid = 0;
64693f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
647c694cb4cSShashi Mallela }
648c694cb4cSShashi Mallela 
process_vmapti(GICv3ITSState * s,const uint64_t * cmdpkt,bool ignore_vintid)6499de53de6SPeter Maydell static ItsCmdResult process_vmapti(GICv3ITSState *s, const uint64_t *cmdpkt,
6509de53de6SPeter Maydell                                    bool ignore_vintid)
6519de53de6SPeter Maydell {
6529de53de6SPeter Maydell     uint32_t devid, eventid, vintid, doorbell, vpeid;
6539de53de6SPeter Maydell     uint32_t num_eventids;
6549678b9c5SPeter Maydell     DTEntry dte = {};
6559678b9c5SPeter Maydell     ITEntry ite = {};
6569de53de6SPeter Maydell 
6579de53de6SPeter Maydell     if (!its_feature_virtual(s)) {
6589de53de6SPeter Maydell         return CMD_CONTINUE;
6599de53de6SPeter Maydell     }
6609de53de6SPeter Maydell 
6619de53de6SPeter Maydell     devid = FIELD_EX64(cmdpkt[0], VMAPTI_0, DEVICEID);
6629de53de6SPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], VMAPTI_1, EVENTID);
6639de53de6SPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VMAPTI_1, VPEID);
6649de53de6SPeter Maydell     doorbell = FIELD_EX64(cmdpkt[2], VMAPTI_2, DOORBELL);
6659de53de6SPeter Maydell     if (ignore_vintid) {
6669de53de6SPeter Maydell         vintid = eventid;
6679de53de6SPeter Maydell         trace_gicv3_its_cmd_vmapi(devid, eventid, vpeid, doorbell);
6689de53de6SPeter Maydell     } else {
6699de53de6SPeter Maydell         vintid = FIELD_EX64(cmdpkt[2], VMAPTI_2, VINTID);
6709de53de6SPeter Maydell         trace_gicv3_its_cmd_vmapti(devid, eventid, vpeid, vintid, doorbell);
6719de53de6SPeter Maydell     }
6729de53de6SPeter Maydell 
6739de53de6SPeter Maydell     if (devid >= s->dt.num_entries) {
6749de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
6759de53de6SPeter Maydell                       "%s: invalid DeviceID 0x%x (must be less than 0x%x)\n",
6769de53de6SPeter Maydell                       __func__, devid, s->dt.num_entries);
6779de53de6SPeter Maydell         return CMD_CONTINUE;
6789de53de6SPeter Maydell     }
6799de53de6SPeter Maydell 
6809de53de6SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
6819de53de6SPeter Maydell         return CMD_STALL;
6829de53de6SPeter Maydell     }
6839de53de6SPeter Maydell 
6849de53de6SPeter Maydell     if (!dte.valid) {
6859de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
6869de53de6SPeter Maydell                       "%s: no entry in device table for DeviceID 0x%x\n",
6879de53de6SPeter Maydell                       __func__, devid);
6889de53de6SPeter Maydell         return CMD_CONTINUE;
6899de53de6SPeter Maydell     }
6909de53de6SPeter Maydell 
6919de53de6SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
6929de53de6SPeter Maydell 
6939de53de6SPeter Maydell     if (eventid >= num_eventids) {
6949de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
6959de53de6SPeter Maydell                       "%s: EventID 0x%x too large for DeviceID 0x%x "
6969de53de6SPeter Maydell                       "(must be less than 0x%x)\n",
6979de53de6SPeter Maydell                       __func__, eventid, devid, num_eventids);
6989de53de6SPeter Maydell         return CMD_CONTINUE;
6999de53de6SPeter Maydell     }
7009de53de6SPeter Maydell     if (!intid_in_lpi_range(vintid)) {
7019de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
7029de53de6SPeter Maydell                       "%s: VIntID 0x%x not a valid LPI\n",
7039de53de6SPeter Maydell                       __func__, vintid);
7049de53de6SPeter Maydell         return CMD_CONTINUE;
7059de53de6SPeter Maydell     }
7069de53de6SPeter Maydell     if (!valid_doorbell(doorbell)) {
7079de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
7089de53de6SPeter Maydell                       "%s: Doorbell %d not 1023 and not a valid LPI\n",
7099de53de6SPeter Maydell                       __func__, doorbell);
7109de53de6SPeter Maydell         return CMD_CONTINUE;
7119de53de6SPeter Maydell     }
7129de53de6SPeter Maydell     if (vpeid >= s->vpet.num_entries) {
7139de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
7149de53de6SPeter Maydell                       "%s: VPEID 0x%x out of range (must be less than 0x%x)\n",
7159de53de6SPeter Maydell                       __func__, vpeid, s->vpet.num_entries);
7169de53de6SPeter Maydell         return CMD_CONTINUE;
7179de53de6SPeter Maydell     }
7189de53de6SPeter Maydell     /* add ite entry to interrupt translation table */
7199de53de6SPeter Maydell     ite.valid = true;
7209de53de6SPeter Maydell     ite.inttype = ITE_INTTYPE_VIRTUAL;
7219de53de6SPeter Maydell     ite.intid = vintid;
7229de53de6SPeter Maydell     ite.icid = 0;
7239de53de6SPeter Maydell     ite.doorbell = doorbell;
7249de53de6SPeter Maydell     ite.vpeid = vpeid;
72593f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
7269de53de6SPeter Maydell }
7279de53de6SPeter Maydell 
72806985cc3SPeter Maydell /*
72906985cc3SPeter Maydell  * Update the Collection Table entry for @icid to @cte. Returns true
73006985cc3SPeter Maydell  * on success, false if there was a memory access error.
73106985cc3SPeter Maydell  */
update_cte(GICv3ITSState * s,uint16_t icid,const CTEntry * cte)73206985cc3SPeter Maydell static bool update_cte(GICv3ITSState *s, uint16_t icid, const CTEntry *cte)
7337eca39e0SShashi Mallela {
7347eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
735d050f80fSPeter Maydell     uint64_t entry_addr;
73606985cc3SPeter Maydell     uint64_t cteval = 0;
7377eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
7387eca39e0SShashi Mallela 
739930f40e9SPeter Maydell     trace_gicv3_its_cte_write(icid, cte->valid, cte->rdbase);
740930f40e9SPeter Maydell 
74106985cc3SPeter Maydell     if (cte->valid) {
7427eca39e0SShashi Mallela         /* add mapping entry to collection table */
74306985cc3SPeter Maydell         cteval = FIELD_DP64(cteval, CTE, VALID, 1);
74406985cc3SPeter Maydell         cteval = FIELD_DP64(cteval, CTE, RDBASE, cte->rdbase);
7457eca39e0SShashi Mallela     }
7467eca39e0SShashi Mallela 
747d050f80fSPeter Maydell     entry_addr = table_entry_addr(s, &s->ct, icid, &res);
7487eca39e0SShashi Mallela     if (res != MEMTX_OK) {
749d050f80fSPeter Maydell         /* memory access error: stall */
7507eca39e0SShashi Mallela         return false;
7517eca39e0SShashi Mallela     }
752d050f80fSPeter Maydell     if (entry_addr == -1) {
753d050f80fSPeter Maydell         /* No L2 table for this index: discard write and continue */
7547eca39e0SShashi Mallela         return true;
7557eca39e0SShashi Mallela     }
756d050f80fSPeter Maydell 
75706985cc3SPeter Maydell     address_space_stq_le(as, entry_addr, cteval, MEMTXATTRS_UNSPECIFIED, &res);
758d050f80fSPeter Maydell     return res == MEMTX_OK;
7597eca39e0SShashi Mallela }
7607eca39e0SShashi Mallela 
process_mapc(GICv3ITSState * s,const uint64_t * cmdpkt)761b6f96009SPeter Maydell static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
7627eca39e0SShashi Mallela {
7637eca39e0SShashi Mallela     uint16_t icid;
7649678b9c5SPeter Maydell     CTEntry cte = {};
7657eca39e0SShashi Mallela 
766b6f96009SPeter Maydell     icid = cmdpkt[2] & ICID_MASK;
76784d43d2eSPeter Maydell     cte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
76884d43d2eSPeter Maydell     if (cte.valid) {
76906985cc3SPeter Maydell         cte.rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
77006985cc3SPeter Maydell         cte.rdbase &= RDBASE_PROCNUM_MASK;
77184d43d2eSPeter Maydell     } else {
77284d43d2eSPeter Maydell         cte.rdbase = 0;
77384d43d2eSPeter Maydell     }
774e4050980SPeter Maydell     trace_gicv3_its_cmd_mapc(icid, cte.rdbase, cte.valid);
7757eca39e0SShashi Mallela 
77684d43d2eSPeter Maydell     if (icid >= s->ct.num_entries) {
777c7ca3ad5SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "ITS MAPC: invalid ICID 0x%x\n", icid);
77884d43d2eSPeter Maydell         return CMD_CONTINUE;
77984d43d2eSPeter Maydell     }
78084d43d2eSPeter Maydell     if (cte.valid && cte.rdbase >= s->gicv3->num_cpu) {
7817eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
782c7ca3ad5SPeter Maydell                       "ITS MAPC: invalid RDBASE %u\n", cte.rdbase);
783f6675196SPeter Maydell         return CMD_CONTINUE;
7847eca39e0SShashi Mallela     }
7857eca39e0SShashi Mallela 
78693f4fdcdSPeter Maydell     return update_cte(s, icid, &cte) ? CMD_CONTINUE_OK : CMD_STALL;
7877eca39e0SShashi Mallela }
7887eca39e0SShashi Mallela 
78922d62b08SPeter Maydell /*
79022d62b08SPeter Maydell  * Update the Device Table entry for @devid to @dte. Returns true
79122d62b08SPeter Maydell  * on success, false if there was a memory access error.
79222d62b08SPeter Maydell  */
update_dte(GICv3ITSState * s,uint32_t devid,const DTEntry * dte)79322d62b08SPeter Maydell static bool update_dte(GICv3ITSState *s, uint32_t devid, const DTEntry *dte)
7947eca39e0SShashi Mallela {
7957eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
796d050f80fSPeter Maydell     uint64_t entry_addr;
79722d62b08SPeter Maydell     uint64_t dteval = 0;
7987eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
7997eca39e0SShashi Mallela 
800930f40e9SPeter Maydell     trace_gicv3_its_dte_write(devid, dte->valid, dte->size, dte->ittaddr);
801930f40e9SPeter Maydell 
80222d62b08SPeter Maydell     if (dte->valid) {
8037eca39e0SShashi Mallela         /* add mapping entry to device table */
80422d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, VALID, 1);
80522d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, SIZE, dte->size);
80622d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, ITTADDR, dte->ittaddr);
8077eca39e0SShashi Mallela     }
8087eca39e0SShashi Mallela 
809d050f80fSPeter Maydell     entry_addr = table_entry_addr(s, &s->dt, devid, &res);
8107eca39e0SShashi Mallela     if (res != MEMTX_OK) {
811d050f80fSPeter Maydell         /* memory access error: stall */
8127eca39e0SShashi Mallela         return false;
8137eca39e0SShashi Mallela     }
814d050f80fSPeter Maydell     if (entry_addr == -1) {
815d050f80fSPeter Maydell         /* No L2 table for this index: discard write and continue */
8167eca39e0SShashi Mallela         return true;
8177eca39e0SShashi Mallela     }
81822d62b08SPeter Maydell     address_space_stq_le(as, entry_addr, dteval, MEMTXATTRS_UNSPECIFIED, &res);
819d050f80fSPeter Maydell     return res == MEMTX_OK;
8207eca39e0SShashi Mallela }
8217eca39e0SShashi Mallela 
process_mapd(GICv3ITSState * s,const uint64_t * cmdpkt)822b6f96009SPeter Maydell static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
8237eca39e0SShashi Mallela {
8247eca39e0SShashi Mallela     uint32_t devid;
8259678b9c5SPeter Maydell     DTEntry dte = {};
8267eca39e0SShashi Mallela 
827b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
82822d62b08SPeter Maydell     dte.size = cmdpkt[1] & SIZE_MASK;
82922d62b08SPeter Maydell     dte.ittaddr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
83022d62b08SPeter Maydell     dte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
8317eca39e0SShashi Mallela 
832e4050980SPeter Maydell     trace_gicv3_its_cmd_mapd(devid, dte.size, dte.ittaddr, dte.valid);
833e4050980SPeter Maydell 
834d7d359c4SPeter Maydell     if (devid >= s->dt.num_entries) {
8357eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
836d7d359c4SPeter Maydell                       "ITS MAPD: invalid device ID field 0x%x >= 0x%x\n",
837d7d359c4SPeter Maydell                       devid, s->dt.num_entries);
838d7d359c4SPeter Maydell         return CMD_CONTINUE;
839d7d359c4SPeter Maydell     }
840d7d359c4SPeter Maydell 
841d7d359c4SPeter Maydell     if (dte.size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
842d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
843d7d359c4SPeter Maydell                       "ITS MAPD: invalid size %d\n", dte.size);
84400d46e72SPeter Maydell         return CMD_CONTINUE;
8457eca39e0SShashi Mallela     }
8467eca39e0SShashi Mallela 
84793f4fdcdSPeter Maydell     return update_dte(s, devid, &dte) ? CMD_CONTINUE_OK : CMD_STALL;
8487eca39e0SShashi Mallela }
8497eca39e0SShashi Mallela 
process_movall(GICv3ITSState * s,const uint64_t * cmdpkt)850b6f96009SPeter Maydell static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt)
851f6d1d9b4SPeter Maydell {
852f6d1d9b4SPeter Maydell     uint64_t rd1, rd2;
853f6d1d9b4SPeter Maydell 
854b6f96009SPeter Maydell     rd1 = FIELD_EX64(cmdpkt[2], MOVALL_2, RDBASE1);
855b6f96009SPeter Maydell     rd2 = FIELD_EX64(cmdpkt[3], MOVALL_3, RDBASE2);
856f6d1d9b4SPeter Maydell 
857e4050980SPeter Maydell     trace_gicv3_its_cmd_movall(rd1, rd2);
858e4050980SPeter Maydell 
859f6d1d9b4SPeter Maydell     if (rd1 >= s->gicv3->num_cpu) {
860f6d1d9b4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
861f6d1d9b4SPeter Maydell                       "%s: RDBASE1 %" PRId64
862f6d1d9b4SPeter Maydell                       " out of range (must be less than %d)\n",
863f6d1d9b4SPeter Maydell                       __func__, rd1, s->gicv3->num_cpu);
864f6d1d9b4SPeter Maydell         return CMD_CONTINUE;
865f6d1d9b4SPeter Maydell     }
866f6d1d9b4SPeter Maydell     if (rd2 >= s->gicv3->num_cpu) {
867f6d1d9b4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
868f6d1d9b4SPeter Maydell                       "%s: RDBASE2 %" PRId64
869f6d1d9b4SPeter Maydell                       " out of range (must be less than %d)\n",
870f6d1d9b4SPeter Maydell                       __func__, rd2, s->gicv3->num_cpu);
871f6d1d9b4SPeter Maydell         return CMD_CONTINUE;
872f6d1d9b4SPeter Maydell     }
873f6d1d9b4SPeter Maydell 
874f6d1d9b4SPeter Maydell     if (rd1 == rd2) {
875f6d1d9b4SPeter Maydell         /* Move to same target must succeed as a no-op */
87693f4fdcdSPeter Maydell         return CMD_CONTINUE_OK;
877f6d1d9b4SPeter Maydell     }
878f6d1d9b4SPeter Maydell 
879f6d1d9b4SPeter Maydell     /* Move all pending LPIs from redistributor 1 to redistributor 2 */
880f6d1d9b4SPeter Maydell     gicv3_redist_movall_lpis(&s->gicv3->cpu[rd1], &s->gicv3->cpu[rd2]);
881f6d1d9b4SPeter Maydell 
88293f4fdcdSPeter Maydell     return CMD_CONTINUE_OK;
883f6d1d9b4SPeter Maydell }
884f6d1d9b4SPeter Maydell 
process_movi(GICv3ITSState * s,const uint64_t * cmdpkt)885b6f96009SPeter Maydell static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
886961b4912SPeter Maydell {
887244194feSPeter Maydell     uint32_t devid, eventid;
888244194feSPeter Maydell     uint16_t new_icid;
8899678b9c5SPeter Maydell     DTEntry dte = {};
8909678b9c5SPeter Maydell     CTEntry old_cte = {}, new_cte = {};
8919678b9c5SPeter Maydell     ITEntry old_ite = {};
892f0175135SPeter Maydell     ItsCmdResult cmdres;
893961b4912SPeter Maydell 
894b6f96009SPeter Maydell     devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID);
895b6f96009SPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID);
896b6f96009SPeter Maydell     new_icid = FIELD_EX64(cmdpkt[2], MOVI_2, ICID);
897961b4912SPeter Maydell 
898e4050980SPeter Maydell     trace_gicv3_its_cmd_movi(devid, eventid, new_icid);
899e4050980SPeter Maydell 
900f0175135SPeter Maydell     cmdres = lookup_ite(s, __func__, devid, eventid, &old_ite, &dte);
901f0175135SPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
902f0175135SPeter Maydell         return cmdres;
903961b4912SPeter Maydell     }
904961b4912SPeter Maydell 
905f0175135SPeter Maydell     if (old_ite.inttype != ITE_INTTYPE_PHYSICAL) {
906961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
907961b4912SPeter Maydell                       "%s: invalid command attributes: invalid ITE\n",
908961b4912SPeter Maydell                       __func__);
909961b4912SPeter Maydell         return CMD_CONTINUE;
910961b4912SPeter Maydell     }
911961b4912SPeter Maydell 
912c411db7bSPeter Maydell     cmdres = lookup_cte(s, __func__, old_ite.icid, &old_cte);
913c411db7bSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
914c411db7bSPeter Maydell         return cmdres;
915961b4912SPeter Maydell     }
916c411db7bSPeter Maydell     cmdres = lookup_cte(s, __func__, new_icid, &new_cte);
917c411db7bSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
918c411db7bSPeter Maydell         return cmdres;
919961b4912SPeter Maydell     }
920961b4912SPeter Maydell 
921d37cf49bSPeter Maydell     if (old_cte.rdbase != new_cte.rdbase) {
922961b4912SPeter Maydell         /* Move the LPI from the old redistributor to the new one */
923d37cf49bSPeter Maydell         gicv3_redist_mov_lpi(&s->gicv3->cpu[old_cte.rdbase],
924d37cf49bSPeter Maydell                              &s->gicv3->cpu[new_cte.rdbase],
925244194feSPeter Maydell                              old_ite.intid);
926961b4912SPeter Maydell     }
927961b4912SPeter Maydell 
928961b4912SPeter Maydell     /* Update the ICID field in the interrupt translation table entry */
9297eb54267SPeter Maydell     old_ite.icid = new_icid;
93093f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &old_ite) ? CMD_CONTINUE_OK : CMD_STALL;
931961b4912SPeter Maydell }
932961b4912SPeter Maydell 
9337eca39e0SShashi Mallela /*
9340cdf7a5dSPeter Maydell  * Update the vPE Table entry at index @vpeid with the entry @vte.
9350cdf7a5dSPeter Maydell  * Returns true on success, false if there was a memory access error.
9360cdf7a5dSPeter Maydell  */
update_vte(GICv3ITSState * s,uint32_t vpeid,const VTEntry * vte)9370cdf7a5dSPeter Maydell static bool update_vte(GICv3ITSState *s, uint32_t vpeid, const VTEntry *vte)
9380cdf7a5dSPeter Maydell {
9390cdf7a5dSPeter Maydell     AddressSpace *as = &s->gicv3->dma_as;
9400cdf7a5dSPeter Maydell     uint64_t entry_addr;
9410cdf7a5dSPeter Maydell     uint64_t vteval = 0;
9420cdf7a5dSPeter Maydell     MemTxResult res = MEMTX_OK;
9430cdf7a5dSPeter Maydell 
9440cdf7a5dSPeter Maydell     trace_gicv3_its_vte_write(vpeid, vte->valid, vte->vptsize, vte->vptaddr,
9450cdf7a5dSPeter Maydell                               vte->rdbase);
9460cdf7a5dSPeter Maydell 
9470cdf7a5dSPeter Maydell     if (vte->valid) {
9480cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VALID, 1);
9490cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VPTSIZE, vte->vptsize);
9500cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VPTADDR, vte->vptaddr);
9510cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, RDBASE, vte->rdbase);
9520cdf7a5dSPeter Maydell     }
9530cdf7a5dSPeter Maydell 
9540cdf7a5dSPeter Maydell     entry_addr = table_entry_addr(s, &s->vpet, vpeid, &res);
9550cdf7a5dSPeter Maydell     if (res != MEMTX_OK) {
9560cdf7a5dSPeter Maydell         return false;
9570cdf7a5dSPeter Maydell     }
9580cdf7a5dSPeter Maydell     if (entry_addr == -1) {
9590cdf7a5dSPeter Maydell         /* No L2 table for this index: discard write and continue */
9600cdf7a5dSPeter Maydell         return true;
9610cdf7a5dSPeter Maydell     }
9620cdf7a5dSPeter Maydell     address_space_stq_le(as, entry_addr, vteval, MEMTXATTRS_UNSPECIFIED, &res);
9630cdf7a5dSPeter Maydell     return res == MEMTX_OK;
9640cdf7a5dSPeter Maydell }
9650cdf7a5dSPeter Maydell 
process_vmapp(GICv3ITSState * s,const uint64_t * cmdpkt)9660cdf7a5dSPeter Maydell static ItsCmdResult process_vmapp(GICv3ITSState *s, const uint64_t *cmdpkt)
9670cdf7a5dSPeter Maydell {
9689678b9c5SPeter Maydell     VTEntry vte = {};
9690cdf7a5dSPeter Maydell     uint32_t vpeid;
9700cdf7a5dSPeter Maydell 
9710cdf7a5dSPeter Maydell     if (!its_feature_virtual(s)) {
9720cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9730cdf7a5dSPeter Maydell     }
9740cdf7a5dSPeter Maydell 
9750cdf7a5dSPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VMAPP_1, VPEID);
9760cdf7a5dSPeter Maydell     vte.rdbase = FIELD_EX64(cmdpkt[2], VMAPP_2, RDBASE);
9770cdf7a5dSPeter Maydell     vte.valid = FIELD_EX64(cmdpkt[2], VMAPP_2, V);
9780cdf7a5dSPeter Maydell     vte.vptsize = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTSIZE);
9790cdf7a5dSPeter Maydell     vte.vptaddr = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTADDR);
9800cdf7a5dSPeter Maydell 
9810cdf7a5dSPeter Maydell     trace_gicv3_its_cmd_vmapp(vpeid, vte.rdbase, vte.valid,
9820cdf7a5dSPeter Maydell                               vte.vptaddr, vte.vptsize);
9830cdf7a5dSPeter Maydell 
9840cdf7a5dSPeter Maydell     /*
9850cdf7a5dSPeter Maydell      * For GICv4.0 the VPT_size field is only 5 bits, whereas we
9860cdf7a5dSPeter Maydell      * define our field macros to include the full GICv4.1 8 bits.
9870cdf7a5dSPeter Maydell      * The range check on VPT_size will catch the cases where
9880cdf7a5dSPeter Maydell      * the guest set the RES0-in-GICv4.0 bits [7:6].
9890cdf7a5dSPeter Maydell      */
9900cdf7a5dSPeter Maydell     if (vte.vptsize > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
9910cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
9920cdf7a5dSPeter Maydell                       "%s: invalid VPT_size 0x%x\n", __func__, vte.vptsize);
9930cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9940cdf7a5dSPeter Maydell     }
9950cdf7a5dSPeter Maydell 
9960cdf7a5dSPeter Maydell     if (vte.valid && vte.rdbase >= s->gicv3->num_cpu) {
9970cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
9980cdf7a5dSPeter Maydell                       "%s: invalid rdbase 0x%x\n", __func__, vte.rdbase);
9990cdf7a5dSPeter Maydell         return CMD_CONTINUE;
10000cdf7a5dSPeter Maydell     }
10010cdf7a5dSPeter Maydell 
10020cdf7a5dSPeter Maydell     if (vpeid >= s->vpet.num_entries) {
10030cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
10040cdf7a5dSPeter Maydell                       "%s: VPEID 0x%x out of range (must be less than 0x%x)\n",
10050cdf7a5dSPeter Maydell                       __func__, vpeid, s->vpet.num_entries);
10060cdf7a5dSPeter Maydell         return CMD_CONTINUE;
10070cdf7a5dSPeter Maydell     }
10080cdf7a5dSPeter Maydell 
100993f4fdcdSPeter Maydell     return update_vte(s, vpeid, &vte) ? CMD_CONTINUE_OK : CMD_STALL;
10100cdf7a5dSPeter Maydell }
10110cdf7a5dSPeter Maydell 
10123851af45SPeter Maydell typedef struct VmovpCallbackData {
10133851af45SPeter Maydell     uint64_t rdbase;
10143851af45SPeter Maydell     uint32_t vpeid;
10153851af45SPeter Maydell     /*
10163851af45SPeter Maydell      * Overall command result. If more than one callback finds an
10173851af45SPeter Maydell      * error, STALL beats CONTINUE.
10183851af45SPeter Maydell      */
10193851af45SPeter Maydell     ItsCmdResult result;
10203851af45SPeter Maydell } VmovpCallbackData;
10213851af45SPeter Maydell 
vmovp_callback(gpointer data,gpointer opaque)10223851af45SPeter Maydell static void vmovp_callback(gpointer data, gpointer opaque)
10233851af45SPeter Maydell {
10243851af45SPeter Maydell     /*
10253851af45SPeter Maydell      * This function is called to update the VPEID field in a VPE
10263851af45SPeter Maydell      * table entry for this ITS. This might be because of a VMOVP
10273851af45SPeter Maydell      * command executed on any ITS that is connected to the same GIC
10283851af45SPeter Maydell      * as this ITS.  We need to read the VPE table entry for the VPEID
10293851af45SPeter Maydell      * and update its RDBASE field.
10303851af45SPeter Maydell      */
10313851af45SPeter Maydell     GICv3ITSState *s = data;
10323851af45SPeter Maydell     VmovpCallbackData *cbdata = opaque;
10339678b9c5SPeter Maydell     VTEntry vte = {};
10343851af45SPeter Maydell     ItsCmdResult cmdres;
10353851af45SPeter Maydell 
10363851af45SPeter Maydell     cmdres = lookup_vte(s, __func__, cbdata->vpeid, &vte);
10373851af45SPeter Maydell     switch (cmdres) {
10383851af45SPeter Maydell     case CMD_STALL:
10393851af45SPeter Maydell         cbdata->result = CMD_STALL;
10403851af45SPeter Maydell         return;
10413851af45SPeter Maydell     case CMD_CONTINUE:
10423851af45SPeter Maydell         if (cbdata->result != CMD_STALL) {
10433851af45SPeter Maydell             cbdata->result = CMD_CONTINUE;
10443851af45SPeter Maydell         }
10453851af45SPeter Maydell         return;
10463851af45SPeter Maydell     case CMD_CONTINUE_OK:
10473851af45SPeter Maydell         break;
10483851af45SPeter Maydell     }
10493851af45SPeter Maydell 
10503851af45SPeter Maydell     vte.rdbase = cbdata->rdbase;
10513851af45SPeter Maydell     if (!update_vte(s, cbdata->vpeid, &vte)) {
10523851af45SPeter Maydell         cbdata->result = CMD_STALL;
10533851af45SPeter Maydell     }
10543851af45SPeter Maydell }
10553851af45SPeter Maydell 
process_vmovp(GICv3ITSState * s,const uint64_t * cmdpkt)10563851af45SPeter Maydell static ItsCmdResult process_vmovp(GICv3ITSState *s, const uint64_t *cmdpkt)
10573851af45SPeter Maydell {
10583851af45SPeter Maydell     VmovpCallbackData cbdata;
10593851af45SPeter Maydell 
10603851af45SPeter Maydell     if (!its_feature_virtual(s)) {
10613851af45SPeter Maydell         return CMD_CONTINUE;
10623851af45SPeter Maydell     }
10633851af45SPeter Maydell 
10643851af45SPeter Maydell     cbdata.vpeid = FIELD_EX64(cmdpkt[1], VMOVP_1, VPEID);
10653851af45SPeter Maydell     cbdata.rdbase = FIELD_EX64(cmdpkt[2], VMOVP_2, RDBASE);
10663851af45SPeter Maydell 
10673851af45SPeter Maydell     trace_gicv3_its_cmd_vmovp(cbdata.vpeid, cbdata.rdbase);
10683851af45SPeter Maydell 
10693851af45SPeter Maydell     if (cbdata.rdbase >= s->gicv3->num_cpu) {
10703851af45SPeter Maydell         return CMD_CONTINUE;
10713851af45SPeter Maydell     }
10723851af45SPeter Maydell 
10733851af45SPeter Maydell     /*
10743851af45SPeter Maydell      * Our ITS implementation reports GITS_TYPER.VMOVP == 1, which means
10753851af45SPeter Maydell      * that when the VMOVP command is executed on an ITS to change the
10763851af45SPeter Maydell      * VPEID field in a VPE table entry the change must be propagated
10773851af45SPeter Maydell      * to all the ITSes connected to the same GIC.
10783851af45SPeter Maydell      */
10793851af45SPeter Maydell     cbdata.result = CMD_CONTINUE_OK;
10803851af45SPeter Maydell     gicv3_foreach_its(s->gicv3, vmovp_callback, &cbdata);
10813851af45SPeter Maydell     return cbdata.result;
10823851af45SPeter Maydell }
10833851af45SPeter Maydell 
process_vmovi(GICv3ITSState * s,const uint64_t * cmdpkt)10843c64a42cSPeter Maydell static ItsCmdResult process_vmovi(GICv3ITSState *s, const uint64_t *cmdpkt)
10853c64a42cSPeter Maydell {
10863c64a42cSPeter Maydell     uint32_t devid, eventid, vpeid, doorbell;
10873c64a42cSPeter Maydell     bool doorbell_valid;
10889678b9c5SPeter Maydell     DTEntry dte = {};
10899678b9c5SPeter Maydell     ITEntry ite = {};
10909678b9c5SPeter Maydell     VTEntry old_vte = {}, new_vte = {};
10913c64a42cSPeter Maydell     ItsCmdResult cmdres;
10923c64a42cSPeter Maydell 
10933c64a42cSPeter Maydell     if (!its_feature_virtual(s)) {
10943c64a42cSPeter Maydell         return CMD_CONTINUE;
10953c64a42cSPeter Maydell     }
10963c64a42cSPeter Maydell 
10973c64a42cSPeter Maydell     devid = FIELD_EX64(cmdpkt[0], VMOVI_0, DEVICEID);
10983c64a42cSPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], VMOVI_1, EVENTID);
10993c64a42cSPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VMOVI_1, VPEID);
11003c64a42cSPeter Maydell     doorbell_valid = FIELD_EX64(cmdpkt[2], VMOVI_2, D);
11013c64a42cSPeter Maydell     doorbell = FIELD_EX64(cmdpkt[2], VMOVI_2, DOORBELL);
11023c64a42cSPeter Maydell 
11033c64a42cSPeter Maydell     trace_gicv3_its_cmd_vmovi(devid, eventid, vpeid, doorbell_valid, doorbell);
11043c64a42cSPeter Maydell 
11053c64a42cSPeter Maydell     if (doorbell_valid && !valid_doorbell(doorbell)) {
11063c64a42cSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
11073c64a42cSPeter Maydell                       "%s: invalid doorbell 0x%x\n", __func__, doorbell);
11083c64a42cSPeter Maydell         return CMD_CONTINUE;
11093c64a42cSPeter Maydell     }
11103c64a42cSPeter Maydell 
11113c64a42cSPeter Maydell     cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte);
11123c64a42cSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
11133c64a42cSPeter Maydell         return cmdres;
11143c64a42cSPeter Maydell     }
11153c64a42cSPeter Maydell 
11163c64a42cSPeter Maydell     if (ite.inttype != ITE_INTTYPE_VIRTUAL) {
11173c64a42cSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "%s: ITE is not for virtual interrupt\n",
11183c64a42cSPeter Maydell                       __func__);
11193c64a42cSPeter Maydell         return CMD_CONTINUE;
11203c64a42cSPeter Maydell     }
11213c64a42cSPeter Maydell 
11223c64a42cSPeter Maydell     cmdres = lookup_vte(s, __func__, ite.vpeid, &old_vte);
11233c64a42cSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
11243c64a42cSPeter Maydell         return cmdres;
11253c64a42cSPeter Maydell     }
11263c64a42cSPeter Maydell     cmdres = lookup_vte(s, __func__, vpeid, &new_vte);
11273c64a42cSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
11283c64a42cSPeter Maydell         return cmdres;
11293c64a42cSPeter Maydell     }
11303c64a42cSPeter Maydell 
11313c64a42cSPeter Maydell     if (!intid_in_lpi_range(ite.intid) ||
11323c64a42cSPeter Maydell         ite.intid >= (1ULL << (old_vte.vptsize + 1)) ||
11333c64a42cSPeter Maydell         ite.intid >= (1ULL << (new_vte.vptsize + 1))) {
11343c64a42cSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
11353c64a42cSPeter Maydell                       "%s: ITE intid 0x%x out of range\n",
11363c64a42cSPeter Maydell                       __func__, ite.intid);
11373c64a42cSPeter Maydell         return CMD_CONTINUE;
11383c64a42cSPeter Maydell     }
11393c64a42cSPeter Maydell 
11403c64a42cSPeter Maydell     ite.vpeid = vpeid;
11413c64a42cSPeter Maydell     if (doorbell_valid) {
11423c64a42cSPeter Maydell         ite.doorbell = doorbell;
11433c64a42cSPeter Maydell     }
11443c64a42cSPeter Maydell 
11453c64a42cSPeter Maydell     /*
11463c64a42cSPeter Maydell      * Move the LPI from the old redistributor to the new one. We don't
11473c64a42cSPeter Maydell      * need to do anything if the guest somehow specified the
11483c64a42cSPeter Maydell      * same pending table for source and destination.
11493c64a42cSPeter Maydell      */
11503c64a42cSPeter Maydell     if (old_vte.vptaddr != new_vte.vptaddr) {
11513c64a42cSPeter Maydell         gicv3_redist_mov_vlpi(&s->gicv3->cpu[old_vte.rdbase],
11523c64a42cSPeter Maydell                               old_vte.vptaddr << 16,
11533c64a42cSPeter Maydell                               &s->gicv3->cpu[new_vte.rdbase],
11543c64a42cSPeter Maydell                               new_vte.vptaddr << 16,
11553c64a42cSPeter Maydell                               ite.intid,
11563c64a42cSPeter Maydell                               ite.doorbell);
11573c64a42cSPeter Maydell     }
11583c64a42cSPeter Maydell 
11593c64a42cSPeter Maydell     /* Update the ITE to the new VPEID and possibly doorbell values */
11603c64a42cSPeter Maydell     return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
11613c64a42cSPeter Maydell }
11623c64a42cSPeter Maydell 
process_vinvall(GICv3ITSState * s,const uint64_t * cmdpkt)1163c6dd2f99SPeter Maydell static ItsCmdResult process_vinvall(GICv3ITSState *s, const uint64_t *cmdpkt)
1164c6dd2f99SPeter Maydell {
1165c6dd2f99SPeter Maydell     VTEntry vte;
1166c6dd2f99SPeter Maydell     uint32_t vpeid;
1167c6dd2f99SPeter Maydell     ItsCmdResult cmdres;
1168c6dd2f99SPeter Maydell 
1169c6dd2f99SPeter Maydell     if (!its_feature_virtual(s)) {
1170c6dd2f99SPeter Maydell         return CMD_CONTINUE;
1171c6dd2f99SPeter Maydell     }
1172c6dd2f99SPeter Maydell 
1173c6dd2f99SPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VINVALL_1, VPEID);
1174c6dd2f99SPeter Maydell 
1175c6dd2f99SPeter Maydell     trace_gicv3_its_cmd_vinvall(vpeid);
1176c6dd2f99SPeter Maydell 
1177c6dd2f99SPeter Maydell     cmdres = lookup_vte(s, __func__, vpeid, &vte);
1178c6dd2f99SPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
1179c6dd2f99SPeter Maydell         return cmdres;
1180c6dd2f99SPeter Maydell     }
1181c6dd2f99SPeter Maydell 
1182c6dd2f99SPeter Maydell     gicv3_redist_vinvall(&s->gicv3->cpu[vte.rdbase], vte.vptaddr << 16);
1183c6dd2f99SPeter Maydell     return CMD_CONTINUE_OK;
1184c6dd2f99SPeter Maydell }
1185c6dd2f99SPeter Maydell 
process_inv(GICv3ITSState * s,const uint64_t * cmdpkt)1186a686e85dSPeter Maydell static ItsCmdResult process_inv(GICv3ITSState *s, const uint64_t *cmdpkt)
1187a686e85dSPeter Maydell {
1188a686e85dSPeter Maydell     uint32_t devid, eventid;
11899678b9c5SPeter Maydell     ITEntry ite = {};
11909678b9c5SPeter Maydell     DTEntry dte = {};
11919678b9c5SPeter Maydell     CTEntry cte = {};
11929678b9c5SPeter Maydell     VTEntry vte = {};
1193a686e85dSPeter Maydell     ItsCmdResult cmdres;
1194a686e85dSPeter Maydell 
1195a686e85dSPeter Maydell     devid = FIELD_EX64(cmdpkt[0], INV_0, DEVICEID);
1196a686e85dSPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], INV_1, EVENTID);
1197a686e85dSPeter Maydell 
1198a686e85dSPeter Maydell     trace_gicv3_its_cmd_inv(devid, eventid);
1199a686e85dSPeter Maydell 
1200a686e85dSPeter Maydell     cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte);
1201a686e85dSPeter Maydell     if (cmdres != CMD_CONTINUE_OK) {
1202a686e85dSPeter Maydell         return cmdres;
1203a686e85dSPeter Maydell     }
1204a686e85dSPeter Maydell 
1205a686e85dSPeter Maydell     switch (ite.inttype) {
1206a686e85dSPeter Maydell     case ITE_INTTYPE_PHYSICAL:
1207a686e85dSPeter Maydell         cmdres = lookup_cte(s, __func__, ite.icid, &cte);
1208a686e85dSPeter Maydell         if (cmdres != CMD_CONTINUE_OK) {
1209a686e85dSPeter Maydell             return cmdres;
1210a686e85dSPeter Maydell         }
1211a686e85dSPeter Maydell         gicv3_redist_inv_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid);
1212a686e85dSPeter Maydell         break;
1213a686e85dSPeter Maydell     case ITE_INTTYPE_VIRTUAL:
1214a686e85dSPeter Maydell         if (!its_feature_virtual(s)) {
1215a686e85dSPeter Maydell             /* Can't happen unless guest is illegally writing to table memory */
1216a686e85dSPeter Maydell             qemu_log_mask(LOG_GUEST_ERROR,
1217a686e85dSPeter Maydell                           "%s: invalid type %d in ITE (table corrupted?)\n",
1218a686e85dSPeter Maydell                           __func__, ite.inttype);
1219a686e85dSPeter Maydell             return CMD_CONTINUE;
1220a686e85dSPeter Maydell         }
1221d4014320SPeter Maydell 
1222d4014320SPeter Maydell         cmdres = lookup_vte(s, __func__, ite.vpeid, &vte);
1223d4014320SPeter Maydell         if (cmdres != CMD_CONTINUE_OK) {
1224d4014320SPeter Maydell             return cmdres;
1225d4014320SPeter Maydell         }
1226d4014320SPeter Maydell         if (!intid_in_lpi_range(ite.intid) ||
1227d4014320SPeter Maydell             ite.intid >= (1ULL << (vte.vptsize + 1))) {
1228d4014320SPeter Maydell             qemu_log_mask(LOG_GUEST_ERROR, "%s: intid 0x%x out of range\n",
1229d4014320SPeter Maydell                           __func__, ite.intid);
1230d4014320SPeter Maydell             return CMD_CONTINUE;
1231d4014320SPeter Maydell         }
1232d4014320SPeter Maydell         gicv3_redist_inv_vlpi(&s->gicv3->cpu[vte.rdbase], ite.intid,
1233d4014320SPeter Maydell                               vte.vptaddr << 16);
1234a686e85dSPeter Maydell         break;
1235a686e85dSPeter Maydell     default:
1236a686e85dSPeter Maydell         g_assert_not_reached();
1237a686e85dSPeter Maydell     }
1238a686e85dSPeter Maydell 
1239a686e85dSPeter Maydell     return CMD_CONTINUE_OK;
1240a686e85dSPeter Maydell }
1241a686e85dSPeter Maydell 
12420cdf7a5dSPeter Maydell /*
12437eca39e0SShashi Mallela  * Current implementation blocks until all
12447eca39e0SShashi Mallela  * commands are processed
12457eca39e0SShashi Mallela  */
process_cmdq(GICv3ITSState * s)12467eca39e0SShashi Mallela static void process_cmdq(GICv3ITSState *s)
12477eca39e0SShashi Mallela {
12487eca39e0SShashi Mallela     uint32_t wr_offset = 0;
12497eca39e0SShashi Mallela     uint32_t rd_offset = 0;
12507eca39e0SShashi Mallela     uint32_t cq_offset = 0;
12517eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
12527eca39e0SShashi Mallela     uint8_t cmd;
125317fb5e36SShashi Mallela     int i;
12547eca39e0SShashi Mallela 
12558d2d6dd9SPeter Maydell     if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
12567eca39e0SShashi Mallela         return;
12577eca39e0SShashi Mallela     }
12587eca39e0SShashi Mallela 
12597eca39e0SShashi Mallela     wr_offset = FIELD_EX64(s->cwriter, GITS_CWRITER, OFFSET);
12607eca39e0SShashi Mallela 
126180dcd37fSPeter Maydell     if (wr_offset >= s->cq.num_entries) {
12627eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
12637eca39e0SShashi Mallela                       "%s: invalid write offset "
12647eca39e0SShashi Mallela                       "%d\n", __func__, wr_offset);
12657eca39e0SShashi Mallela         return;
12667eca39e0SShashi Mallela     }
12677eca39e0SShashi Mallela 
12687eca39e0SShashi Mallela     rd_offset = FIELD_EX64(s->creadr, GITS_CREADR, OFFSET);
12697eca39e0SShashi Mallela 
127080dcd37fSPeter Maydell     if (rd_offset >= s->cq.num_entries) {
12717eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
12727eca39e0SShashi Mallela                       "%s: invalid read offset "
12737eca39e0SShashi Mallela                       "%d\n", __func__, rd_offset);
12747eca39e0SShashi Mallela         return;
12757eca39e0SShashi Mallela     }
12767eca39e0SShashi Mallela 
12777eca39e0SShashi Mallela     while (wr_offset != rd_offset) {
127893f4fdcdSPeter Maydell         ItsCmdResult result = CMD_CONTINUE_OK;
1279b6f96009SPeter Maydell         void *hostmem;
1280b6f96009SPeter Maydell         hwaddr buflen;
1281b6f96009SPeter Maydell         uint64_t cmdpkt[GITS_CMDQ_ENTRY_WORDS];
1282ef011555SPeter Maydell 
12837eca39e0SShashi Mallela         cq_offset = (rd_offset * GITS_CMDQ_ENTRY_SIZE);
1284b6f96009SPeter Maydell 
1285b6f96009SPeter Maydell         buflen = GITS_CMDQ_ENTRY_SIZE;
1286b6f96009SPeter Maydell         hostmem = address_space_map(as, s->cq.base_addr + cq_offset,
1287b6f96009SPeter Maydell                                     &buflen, false, MEMTXATTRS_UNSPECIFIED);
1288b6f96009SPeter Maydell         if (!hostmem || buflen != GITS_CMDQ_ENTRY_SIZE) {
1289b6f96009SPeter Maydell             if (hostmem) {
1290b6f96009SPeter Maydell                 address_space_unmap(as, hostmem, buflen, false, 0);
1291b6f96009SPeter Maydell             }
1292f0b4b2a2SPeter Maydell             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
1293f0b4b2a2SPeter Maydell             qemu_log_mask(LOG_GUEST_ERROR,
1294f0b4b2a2SPeter Maydell                           "%s: could not read command at 0x%" PRIx64 "\n",
1295f0b4b2a2SPeter Maydell                           __func__, s->cq.base_addr + cq_offset);
1296f0b4b2a2SPeter Maydell             break;
12977eca39e0SShashi Mallela         }
1298b6f96009SPeter Maydell         for (i = 0; i < ARRAY_SIZE(cmdpkt); i++) {
1299b6f96009SPeter Maydell             cmdpkt[i] = ldq_le_p(hostmem + i * sizeof(uint64_t));
1300b6f96009SPeter Maydell         }
1301b6f96009SPeter Maydell         address_space_unmap(as, hostmem, buflen, false, 0);
1302f0b4b2a2SPeter Maydell 
1303b6f96009SPeter Maydell         cmd = cmdpkt[0] & CMD_MASK;
13047eca39e0SShashi Mallela 
1305195209d3SPeter Maydell         trace_gicv3_its_process_command(rd_offset, cmd);
1306195209d3SPeter Maydell 
13077eca39e0SShashi Mallela         switch (cmd) {
13087eca39e0SShashi Mallela         case GITS_CMD_INT:
1309b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, INTERRUPT);
13107eca39e0SShashi Mallela             break;
13117eca39e0SShashi Mallela         case GITS_CMD_CLEAR:
1312b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, CLEAR);
13137eca39e0SShashi Mallela             break;
13147eca39e0SShashi Mallela         case GITS_CMD_SYNC:
13157eca39e0SShashi Mallela             /*
13167eca39e0SShashi Mallela              * Current implementation makes a blocking synchronous call
13177eca39e0SShashi Mallela              * for every command issued earlier, hence the internal state
13187eca39e0SShashi Mallela              * is already consistent by the time SYNC command is executed.
13197eca39e0SShashi Mallela              * Hence no further processing is required for SYNC command.
13207eca39e0SShashi Mallela              */
1321e4050980SPeter Maydell             trace_gicv3_its_cmd_sync();
13227eca39e0SShashi Mallela             break;
1323f76ba95aSPeter Maydell         case GITS_CMD_VSYNC:
1324f76ba95aSPeter Maydell             /*
1325f76ba95aSPeter Maydell              * VSYNC also is a nop, because our implementation is always
1326f76ba95aSPeter Maydell              * in sync.
1327f76ba95aSPeter Maydell              */
1328f76ba95aSPeter Maydell             if (!its_feature_virtual(s)) {
1329f76ba95aSPeter Maydell                 result = CMD_CONTINUE;
1330f76ba95aSPeter Maydell                 break;
1331f76ba95aSPeter Maydell             }
1332f76ba95aSPeter Maydell             trace_gicv3_its_cmd_vsync();
1333f76ba95aSPeter Maydell             break;
13347eca39e0SShashi Mallela         case GITS_CMD_MAPD:
1335b6f96009SPeter Maydell             result = process_mapd(s, cmdpkt);
13367eca39e0SShashi Mallela             break;
13377eca39e0SShashi Mallela         case GITS_CMD_MAPC:
1338b6f96009SPeter Maydell             result = process_mapc(s, cmdpkt);
13397eca39e0SShashi Mallela             break;
13407eca39e0SShashi Mallela         case GITS_CMD_MAPTI:
1341b6f96009SPeter Maydell             result = process_mapti(s, cmdpkt, false);
13427eca39e0SShashi Mallela             break;
13437eca39e0SShashi Mallela         case GITS_CMD_MAPI:
1344b6f96009SPeter Maydell             result = process_mapti(s, cmdpkt, true);
13457eca39e0SShashi Mallela             break;
13467eca39e0SShashi Mallela         case GITS_CMD_DISCARD:
1347b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, DISCARD);
13487eca39e0SShashi Mallela             break;
13497eca39e0SShashi Mallela         case GITS_CMD_INV:
1350a686e85dSPeter Maydell             result = process_inv(s, cmdpkt);
1351a686e85dSPeter Maydell             break;
13527eca39e0SShashi Mallela         case GITS_CMD_INVALL:
135317fb5e36SShashi Mallela             /*
135417fb5e36SShashi Mallela              * Current implementation doesn't cache any ITS tables,
135517fb5e36SShashi Mallela              * but the calculated lpi priority information. We only
135617fb5e36SShashi Mallela              * need to trigger lpi priority re-calculation to be in
135717fb5e36SShashi Mallela              * sync with LPI config table or pending table changes.
1358a686e85dSPeter Maydell              * INVALL operates on a collection specified by ICID so
1359a686e85dSPeter Maydell              * it only affects physical LPIs.
136017fb5e36SShashi Mallela              */
1361a686e85dSPeter Maydell             trace_gicv3_its_cmd_invall();
136217fb5e36SShashi Mallela             for (i = 0; i < s->gicv3->num_cpu; i++) {
136317fb5e36SShashi Mallela                 gicv3_redist_update_lpi(&s->gicv3->cpu[i]);
136417fb5e36SShashi Mallela             }
13657eca39e0SShashi Mallela             break;
1366961b4912SPeter Maydell         case GITS_CMD_MOVI:
1367b6f96009SPeter Maydell             result = process_movi(s, cmdpkt);
1368961b4912SPeter Maydell             break;
1369f6d1d9b4SPeter Maydell         case GITS_CMD_MOVALL:
1370b6f96009SPeter Maydell             result = process_movall(s, cmdpkt);
1371f6d1d9b4SPeter Maydell             break;
13729de53de6SPeter Maydell         case GITS_CMD_VMAPTI:
13739de53de6SPeter Maydell             result = process_vmapti(s, cmdpkt, false);
13749de53de6SPeter Maydell             break;
13759de53de6SPeter Maydell         case GITS_CMD_VMAPI:
13769de53de6SPeter Maydell             result = process_vmapti(s, cmdpkt, true);
13779de53de6SPeter Maydell             break;
13780cdf7a5dSPeter Maydell         case GITS_CMD_VMAPP:
13790cdf7a5dSPeter Maydell             result = process_vmapp(s, cmdpkt);
13800cdf7a5dSPeter Maydell             break;
13813851af45SPeter Maydell         case GITS_CMD_VMOVP:
13823851af45SPeter Maydell             result = process_vmovp(s, cmdpkt);
13833851af45SPeter Maydell             break;
13843c64a42cSPeter Maydell         case GITS_CMD_VMOVI:
13853c64a42cSPeter Maydell             result = process_vmovi(s, cmdpkt);
13863c64a42cSPeter Maydell             break;
1387c6dd2f99SPeter Maydell         case GITS_CMD_VINVALL:
1388c6dd2f99SPeter Maydell             result = process_vinvall(s, cmdpkt);
1389c6dd2f99SPeter Maydell             break;
13907eca39e0SShashi Mallela         default:
1391e4050980SPeter Maydell             trace_gicv3_its_cmd_unknown(cmd);
13927eca39e0SShashi Mallela             break;
13937eca39e0SShashi Mallela         }
139493f4fdcdSPeter Maydell         if (result != CMD_STALL) {
139593f4fdcdSPeter Maydell             /* CMD_CONTINUE or CMD_CONTINUE_OK */
13967eca39e0SShashi Mallela             rd_offset++;
139780dcd37fSPeter Maydell             rd_offset %= s->cq.num_entries;
13987eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, OFFSET, rd_offset);
13997eca39e0SShashi Mallela         } else {
1400ef011555SPeter Maydell             /* CMD_STALL */
14017eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
14027eca39e0SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
1403ef011555SPeter Maydell                           "%s: 0x%x cmd processing failed, stalling\n",
1404ef011555SPeter Maydell                           __func__, cmd);
14057eca39e0SShashi Mallela             break;
14067eca39e0SShashi Mallela         }
14077eca39e0SShashi Mallela     }
14087eca39e0SShashi Mallela }
14097eca39e0SShashi Mallela 
14101b08e436SShashi Mallela /*
14111b08e436SShashi Mallela  * This function extracts the ITS Device and Collection table specific
14121b08e436SShashi Mallela  * parameters (like base_addr, size etc) from GITS_BASER register.
14131b08e436SShashi Mallela  * It is called during ITS enable and also during post_load migration
14141b08e436SShashi Mallela  */
extract_table_params(GICv3ITSState * s)14151b08e436SShashi Mallela static void extract_table_params(GICv3ITSState *s)
14161b08e436SShashi Mallela {
14171b08e436SShashi Mallela     uint16_t num_pages = 0;
14181b08e436SShashi Mallela     uint8_t  page_sz_type;
14191b08e436SShashi Mallela     uint8_t type;
14201b08e436SShashi Mallela     uint32_t page_sz = 0;
14211b08e436SShashi Mallela     uint64_t value;
14221b08e436SShashi Mallela 
14231b08e436SShashi Mallela     for (int i = 0; i < 8; i++) {
1424e5487a41SPeter Maydell         TableDesc *td;
1425e5487a41SPeter Maydell         int idbits;
1426e5487a41SPeter Maydell 
14271b08e436SShashi Mallela         value = s->baser[i];
14281b08e436SShashi Mallela 
14291b08e436SShashi Mallela         if (!value) {
14301b08e436SShashi Mallela             continue;
14311b08e436SShashi Mallela         }
14321b08e436SShashi Mallela 
14331b08e436SShashi Mallela         page_sz_type = FIELD_EX64(value, GITS_BASER, PAGESIZE);
14341b08e436SShashi Mallela 
14351b08e436SShashi Mallela         switch (page_sz_type) {
14361b08e436SShashi Mallela         case 0:
14371b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_4K;
14381b08e436SShashi Mallela             break;
14391b08e436SShashi Mallela 
14401b08e436SShashi Mallela         case 1:
14411b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_16K;
14421b08e436SShashi Mallela             break;
14431b08e436SShashi Mallela 
14441b08e436SShashi Mallela         case 2:
14451b08e436SShashi Mallela         case 3:
14461b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_64K;
14471b08e436SShashi Mallela             break;
14481b08e436SShashi Mallela 
14491b08e436SShashi Mallela         default:
14501b08e436SShashi Mallela             g_assert_not_reached();
14511b08e436SShashi Mallela         }
14521b08e436SShashi Mallela 
14531b08e436SShashi Mallela         num_pages = FIELD_EX64(value, GITS_BASER, SIZE) + 1;
14541b08e436SShashi Mallela 
14551b08e436SShashi Mallela         type = FIELD_EX64(value, GITS_BASER, TYPE);
14561b08e436SShashi Mallela 
14571b08e436SShashi Mallela         switch (type) {
14581b08e436SShashi Mallela         case GITS_BASER_TYPE_DEVICE:
1459e5487a41SPeter Maydell             td = &s->dt;
1460e5487a41SPeter Maydell             idbits = FIELD_EX64(s->typer, GITS_TYPER, DEVBITS) + 1;
146162df780eSPeter Maydell             break;
14621b08e436SShashi Mallela         case GITS_BASER_TYPE_COLLECTION:
1463e5487a41SPeter Maydell             td = &s->ct;
14641b08e436SShashi Mallela             if (FIELD_EX64(s->typer, GITS_TYPER, CIL)) {
1465e5487a41SPeter Maydell                 idbits = FIELD_EX64(s->typer, GITS_TYPER, CIDBITS) + 1;
14661b08e436SShashi Mallela             } else {
14671b08e436SShashi Mallela                 /* 16-bit CollectionId supported when CIL == 0 */
1468e5487a41SPeter Maydell                 idbits = 16;
14691b08e436SShashi Mallela             }
14701b08e436SShashi Mallela             break;
147150d84584SPeter Maydell         case GITS_BASER_TYPE_VPE:
147250d84584SPeter Maydell             td = &s->vpet;
147350d84584SPeter Maydell             /*
147450d84584SPeter Maydell              * For QEMU vPEIDs are always 16 bits. (GICv4.1 allows an
147550d84584SPeter Maydell              * implementation to implement fewer bits and report this
147650d84584SPeter Maydell              * via GICD_TYPER2.)
147750d84584SPeter Maydell              */
147850d84584SPeter Maydell             idbits = 16;
147950d84584SPeter Maydell             break;
14801b08e436SShashi Mallela         default:
1481e5487a41SPeter Maydell             /*
1482e5487a41SPeter Maydell              * GITS_BASER<n>.TYPE is read-only, so GITS_BASER_RO_MASK
1483e5487a41SPeter Maydell              * ensures we will only see type values corresponding to
1484e5487a41SPeter Maydell              * the values set up in gicv3_its_reset().
1485e5487a41SPeter Maydell              */
1486e5487a41SPeter Maydell             g_assert_not_reached();
14871b08e436SShashi Mallela         }
1488e5487a41SPeter Maydell 
1489e5487a41SPeter Maydell         memset(td, 0, sizeof(*td));
1490e5487a41SPeter Maydell         /*
1491e5487a41SPeter Maydell          * If GITS_BASER<n>.Valid is 0 for any <n> then we will not process
1492e5487a41SPeter Maydell          * interrupts. (GITS_TYPER.HCC is 0 for this implementation, so we
1493e5487a41SPeter Maydell          * do not have a special case where the GITS_BASER<n>.Valid bit is 0
1494e5487a41SPeter Maydell          * for the register corresponding to the Collection table but we
1495e5487a41SPeter Maydell          * still have to process interrupts using non-memory-backed
1496e5487a41SPeter Maydell          * Collection table entries.)
1497da4680ceSPeter Maydell          * The specification makes it UNPREDICTABLE to enable the ITS without
1498da4680ceSPeter Maydell          * marking each BASER<n> as valid. We choose to handle these as if
1499da4680ceSPeter Maydell          * the table was zero-sized, so commands using the table will fail
1500da4680ceSPeter Maydell          * and interrupts requested via GITS_TRANSLATER writes will be ignored.
1501da4680ceSPeter Maydell          * This happens automatically by leaving the num_entries field at
1502da4680ceSPeter Maydell          * zero, which will be caught by the bounds checks we have before
1503da4680ceSPeter Maydell          * every table lookup anyway.
1504e5487a41SPeter Maydell          */
1505da4680ceSPeter Maydell         if (!FIELD_EX64(value, GITS_BASER, VALID)) {
1506e5487a41SPeter Maydell             continue;
1507e5487a41SPeter Maydell         }
1508e5487a41SPeter Maydell         td->page_sz = page_sz;
1509e5487a41SPeter Maydell         td->indirect = FIELD_EX64(value, GITS_BASER, INDIRECT);
15109ae85431SPeter Maydell         td->entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE) + 1;
1511e5487a41SPeter Maydell         td->base_addr = baser_base_addr(value, page_sz);
1512e5487a41SPeter Maydell         if (!td->indirect) {
151380dcd37fSPeter Maydell             td->num_entries = (num_pages * page_sz) / td->entry_sz;
1514e5487a41SPeter Maydell         } else {
151580dcd37fSPeter Maydell             td->num_entries = (((num_pages * page_sz) /
1516e5487a41SPeter Maydell                                   L1TABLE_ENTRY_SIZE) *
1517e5487a41SPeter Maydell                                  (page_sz / td->entry_sz));
1518e5487a41SPeter Maydell         }
15198b8bb014SPeter Maydell         td->num_entries = MIN(td->num_entries, 1ULL << idbits);
15201b08e436SShashi Mallela     }
15211b08e436SShashi Mallela }
15221b08e436SShashi Mallela 
extract_cmdq_params(GICv3ITSState * s)15231b08e436SShashi Mallela static void extract_cmdq_params(GICv3ITSState *s)
15241b08e436SShashi Mallela {
15251b08e436SShashi Mallela     uint16_t num_pages = 0;
15261b08e436SShashi Mallela     uint64_t value = s->cbaser;
15271b08e436SShashi Mallela 
15281b08e436SShashi Mallela     num_pages = FIELD_EX64(value, GITS_CBASER, SIZE) + 1;
15291b08e436SShashi Mallela 
15301b08e436SShashi Mallela     memset(&s->cq, 0 , sizeof(s->cq));
15311b08e436SShashi Mallela 
1532da4680ceSPeter Maydell     if (FIELD_EX64(value, GITS_CBASER, VALID)) {
153380dcd37fSPeter Maydell         s->cq.num_entries = (num_pages * GITS_PAGE_SIZE_4K) /
15341b08e436SShashi Mallela                              GITS_CMDQ_ENTRY_SIZE;
15351b08e436SShashi Mallela         s->cq.base_addr = FIELD_EX64(value, GITS_CBASER, PHYADDR);
15361b08e436SShashi Mallela         s->cq.base_addr <<= R_GITS_CBASER_PHYADDR_SHIFT;
15371b08e436SShashi Mallela     }
15381b08e436SShashi Mallela }
15391b08e436SShashi Mallela 
gicv3_its_translation_read(void * opaque,hwaddr offset,uint64_t * data,unsigned size,MemTxAttrs attrs)15407e062b98SPeter Maydell static MemTxResult gicv3_its_translation_read(void *opaque, hwaddr offset,
15417e062b98SPeter Maydell                                               uint64_t *data, unsigned size,
15427e062b98SPeter Maydell                                               MemTxAttrs attrs)
15437e062b98SPeter Maydell {
15447e062b98SPeter Maydell     /*
15457e062b98SPeter Maydell      * GITS_TRANSLATER is write-only, and all other addresses
15467e062b98SPeter Maydell      * in the interrupt translation space frame are RES0.
15477e062b98SPeter Maydell      */
15487e062b98SPeter Maydell     *data = 0;
15497e062b98SPeter Maydell     return MEMTX_OK;
15507e062b98SPeter Maydell }
15517e062b98SPeter Maydell 
gicv3_its_translation_write(void * opaque,hwaddr offset,uint64_t data,unsigned size,MemTxAttrs attrs)155218f6290aSShashi Mallela static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
155318f6290aSShashi Mallela                                                uint64_t data, unsigned size,
155418f6290aSShashi Mallela                                                MemTxAttrs attrs)
155518f6290aSShashi Mallela {
1556c694cb4cSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
1557c694cb4cSShashi Mallela     bool result = true;
1558c694cb4cSShashi Mallela 
1559195209d3SPeter Maydell     trace_gicv3_its_translation_write(offset, data, size, attrs.requester_id);
1560195209d3SPeter Maydell 
1561c694cb4cSShashi Mallela     switch (offset) {
1562c694cb4cSShashi Mallela     case GITS_TRANSLATER:
15638d2d6dd9SPeter Maydell         if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
1564b6f96009SPeter Maydell             result = do_process_its_cmd(s, attrs.requester_id, data, NONE);
1565c694cb4cSShashi Mallela         }
1566c694cb4cSShashi Mallela         break;
1567c694cb4cSShashi Mallela     default:
1568c694cb4cSShashi Mallela         break;
1569c694cb4cSShashi Mallela     }
1570c694cb4cSShashi Mallela 
1571c694cb4cSShashi Mallela     if (result) {
157218f6290aSShashi Mallela         return MEMTX_OK;
1573c694cb4cSShashi Mallela     } else {
1574c694cb4cSShashi Mallela         return MEMTX_ERROR;
1575c694cb4cSShashi Mallela     }
157618f6290aSShashi Mallela }
157718f6290aSShashi Mallela 
its_writel(GICv3ITSState * s,hwaddr offset,uint64_t value,MemTxAttrs attrs)157818f6290aSShashi Mallela static bool its_writel(GICv3ITSState *s, hwaddr offset,
157918f6290aSShashi Mallela                               uint64_t value, MemTxAttrs attrs)
158018f6290aSShashi Mallela {
158118f6290aSShashi Mallela     bool result = true;
15821b08e436SShashi Mallela     int index;
158318f6290aSShashi Mallela 
15841b08e436SShashi Mallela     switch (offset) {
15851b08e436SShashi Mallela     case GITS_CTLR:
15862f459cd1SShashi Mallela         if (value & R_GITS_CTLR_ENABLED_MASK) {
15878d2d6dd9SPeter Maydell             s->ctlr |= R_GITS_CTLR_ENABLED_MASK;
15881b08e436SShashi Mallela             extract_table_params(s);
15891b08e436SShashi Mallela             extract_cmdq_params(s);
15907eca39e0SShashi Mallela             process_cmdq(s);
15912f459cd1SShashi Mallela         } else {
15928d2d6dd9SPeter Maydell             s->ctlr &= ~R_GITS_CTLR_ENABLED_MASK;
15931b08e436SShashi Mallela         }
15941b08e436SShashi Mallela         break;
15951b08e436SShashi Mallela     case GITS_CBASER:
15961b08e436SShashi Mallela         /*
15971b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
15981b08e436SShashi Mallela          *                 already enabled
15991b08e436SShashi Mallela          */
16008d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
16011b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 0, 32, value);
16021b08e436SShashi Mallela             s->creadr = 0;
16031b08e436SShashi Mallela         }
16041b08e436SShashi Mallela         break;
16051b08e436SShashi Mallela     case GITS_CBASER + 4:
16061b08e436SShashi Mallela         /*
16071b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
16081b08e436SShashi Mallela          *                 already enabled
16091b08e436SShashi Mallela          */
16108d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
16111b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 32, 32, value);
16121b08e436SShashi Mallela             s->creadr = 0;
16131b08e436SShashi Mallela         }
16141b08e436SShashi Mallela         break;
16151b08e436SShashi Mallela     case GITS_CWRITER:
16161b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 0, 32,
16171b08e436SShashi Mallela                                (value & ~R_GITS_CWRITER_RETRY_MASK));
16187eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
16197eca39e0SShashi Mallela             process_cmdq(s);
16207eca39e0SShashi Mallela         }
16211b08e436SShashi Mallela         break;
16221b08e436SShashi Mallela     case GITS_CWRITER + 4:
16231b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 32, 32, value);
16241b08e436SShashi Mallela         break;
16251b08e436SShashi Mallela     case GITS_CREADR:
16261b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
16271b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 0, 32,
16281b08e436SShashi Mallela                                   (value & ~R_GITS_CREADR_STALLED_MASK));
16291b08e436SShashi Mallela         } else {
16301b08e436SShashi Mallela             /* RO register, ignore the write */
16311b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
16321b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
1633883f2c59SPhilippe Mathieu-Daudé                           HWADDR_FMT_plx "\n", __func__, offset);
16341b08e436SShashi Mallela         }
16351b08e436SShashi Mallela         break;
16361b08e436SShashi Mallela     case GITS_CREADR + 4:
16371b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
16381b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 32, 32, value);
16391b08e436SShashi Mallela         } else {
16401b08e436SShashi Mallela             /* RO register, ignore the write */
16411b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
16421b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
1643883f2c59SPhilippe Mathieu-Daudé                           HWADDR_FMT_plx "\n", __func__, offset);
16441b08e436SShashi Mallela         }
16451b08e436SShashi Mallela         break;
16461b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
16471b08e436SShashi Mallela         /*
16481b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
16491b08e436SShashi Mallela          *                 already enabled
16501b08e436SShashi Mallela          */
16518d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
16521b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
16531b08e436SShashi Mallela 
16540ffe88e6SPeter Maydell             if (s->baser[index] == 0) {
16550ffe88e6SPeter Maydell                 /* Unimplemented GITS_BASERn: RAZ/WI */
16560ffe88e6SPeter Maydell                 break;
16570ffe88e6SPeter Maydell             }
16581b08e436SShashi Mallela             if (offset & 7) {
16591b08e436SShashi Mallela                 value <<= 32;
16601b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
16611b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(0, 32);
16621b08e436SShashi Mallela                 s->baser[index] |= value;
16631b08e436SShashi Mallela             } else {
16641b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
16651b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(32, 32);
16661b08e436SShashi Mallela                 s->baser[index] |= value;
16671b08e436SShashi Mallela             }
16681b08e436SShashi Mallela         }
16691b08e436SShashi Mallela         break;
16701b08e436SShashi Mallela     case GITS_IIDR:
16711b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
16721b08e436SShashi Mallela         /* RO registers, ignore the write */
16731b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
16741b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
1675883f2c59SPhilippe Mathieu-Daudé                       HWADDR_FMT_plx "\n", __func__, offset);
16761b08e436SShashi Mallela         break;
16771b08e436SShashi Mallela     default:
16781b08e436SShashi Mallela         result = false;
16791b08e436SShashi Mallela         break;
16801b08e436SShashi Mallela     }
168118f6290aSShashi Mallela     return result;
168218f6290aSShashi Mallela }
168318f6290aSShashi Mallela 
its_readl(GICv3ITSState * s,hwaddr offset,uint64_t * data,MemTxAttrs attrs)168418f6290aSShashi Mallela static bool its_readl(GICv3ITSState *s, hwaddr offset,
168518f6290aSShashi Mallela                              uint64_t *data, MemTxAttrs attrs)
168618f6290aSShashi Mallela {
168718f6290aSShashi Mallela     bool result = true;
16881b08e436SShashi Mallela     int index;
168918f6290aSShashi Mallela 
16901b08e436SShashi Mallela     switch (offset) {
16911b08e436SShashi Mallela     case GITS_CTLR:
16921b08e436SShashi Mallela         *data = s->ctlr;
16931b08e436SShashi Mallela         break;
16941b08e436SShashi Mallela     case GITS_IIDR:
16951b08e436SShashi Mallela         *data = gicv3_iidr();
16961b08e436SShashi Mallela         break;
16971b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
16981b08e436SShashi Mallela         /* ID registers */
1699e2d5e189SPeter Maydell         *data = gicv3_idreg(s->gicv3, offset - GITS_IDREGS, GICV3_PIDR0_ITS);
17001b08e436SShashi Mallela         break;
17011b08e436SShashi Mallela     case GITS_TYPER:
17021b08e436SShashi Mallela         *data = extract64(s->typer, 0, 32);
17031b08e436SShashi Mallela         break;
17041b08e436SShashi Mallela     case GITS_TYPER + 4:
17051b08e436SShashi Mallela         *data = extract64(s->typer, 32, 32);
17061b08e436SShashi Mallela         break;
17071b08e436SShashi Mallela     case GITS_CBASER:
17081b08e436SShashi Mallela         *data = extract64(s->cbaser, 0, 32);
17091b08e436SShashi Mallela         break;
17101b08e436SShashi Mallela     case GITS_CBASER + 4:
17111b08e436SShashi Mallela         *data = extract64(s->cbaser, 32, 32);
17121b08e436SShashi Mallela         break;
17131b08e436SShashi Mallela     case GITS_CREADR:
17141b08e436SShashi Mallela         *data = extract64(s->creadr, 0, 32);
17151b08e436SShashi Mallela         break;
17161b08e436SShashi Mallela     case GITS_CREADR + 4:
17171b08e436SShashi Mallela         *data = extract64(s->creadr, 32, 32);
17181b08e436SShashi Mallela         break;
17191b08e436SShashi Mallela     case GITS_CWRITER:
17201b08e436SShashi Mallela         *data = extract64(s->cwriter, 0, 32);
17211b08e436SShashi Mallela         break;
17221b08e436SShashi Mallela     case GITS_CWRITER + 4:
17231b08e436SShashi Mallela         *data = extract64(s->cwriter, 32, 32);
17241b08e436SShashi Mallela         break;
17251b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
17261b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
17271b08e436SShashi Mallela         if (offset & 7) {
17281b08e436SShashi Mallela             *data = extract64(s->baser[index], 32, 32);
17291b08e436SShashi Mallela         } else {
17301b08e436SShashi Mallela             *data = extract64(s->baser[index], 0, 32);
17311b08e436SShashi Mallela         }
17321b08e436SShashi Mallela         break;
17331b08e436SShashi Mallela     default:
17341b08e436SShashi Mallela         result = false;
17351b08e436SShashi Mallela         break;
17361b08e436SShashi Mallela     }
173718f6290aSShashi Mallela     return result;
173818f6290aSShashi Mallela }
173918f6290aSShashi Mallela 
its_writell(GICv3ITSState * s,hwaddr offset,uint64_t value,MemTxAttrs attrs)174018f6290aSShashi Mallela static bool its_writell(GICv3ITSState *s, hwaddr offset,
174118f6290aSShashi Mallela                                uint64_t value, MemTxAttrs attrs)
174218f6290aSShashi Mallela {
174318f6290aSShashi Mallela     bool result = true;
17441b08e436SShashi Mallela     int index;
174518f6290aSShashi Mallela 
17461b08e436SShashi Mallela     switch (offset) {
17471b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
17481b08e436SShashi Mallela         /*
17491b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
17501b08e436SShashi Mallela          *                 already enabled
17511b08e436SShashi Mallela          */
17528d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
17531b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
17540ffe88e6SPeter Maydell             if (s->baser[index] == 0) {
17550ffe88e6SPeter Maydell                 /* Unimplemented GITS_BASERn: RAZ/WI */
17560ffe88e6SPeter Maydell                 break;
17570ffe88e6SPeter Maydell             }
17581b08e436SShashi Mallela             s->baser[index] &= GITS_BASER_RO_MASK;
17591b08e436SShashi Mallela             s->baser[index] |= (value & ~GITS_BASER_RO_MASK);
17601b08e436SShashi Mallela         }
17611b08e436SShashi Mallela         break;
17621b08e436SShashi Mallela     case GITS_CBASER:
17631b08e436SShashi Mallela         /*
17641b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
17651b08e436SShashi Mallela          *                 already enabled
17661b08e436SShashi Mallela          */
17678d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
17681b08e436SShashi Mallela             s->cbaser = value;
17691b08e436SShashi Mallela             s->creadr = 0;
17701b08e436SShashi Mallela         }
17711b08e436SShashi Mallela         break;
17721b08e436SShashi Mallela     case GITS_CWRITER:
17731b08e436SShashi Mallela         s->cwriter = value & ~R_GITS_CWRITER_RETRY_MASK;
17747eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
17757eca39e0SShashi Mallela             process_cmdq(s);
17767eca39e0SShashi Mallela         }
17771b08e436SShashi Mallela         break;
17781b08e436SShashi Mallela     case GITS_CREADR:
17791b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
17801b08e436SShashi Mallela             s->creadr = value & ~R_GITS_CREADR_STALLED_MASK;
17811b08e436SShashi Mallela         } else {
17821b08e436SShashi Mallela             /* RO register, ignore the write */
17831b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
17841b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
1785883f2c59SPhilippe Mathieu-Daudé                           HWADDR_FMT_plx "\n", __func__, offset);
17861b08e436SShashi Mallela         }
17871b08e436SShashi Mallela         break;
17881b08e436SShashi Mallela     case GITS_TYPER:
17891b08e436SShashi Mallela         /* RO registers, ignore the write */
17901b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
17911b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
1792883f2c59SPhilippe Mathieu-Daudé                       HWADDR_FMT_plx "\n", __func__, offset);
17931b08e436SShashi Mallela         break;
17941b08e436SShashi Mallela     default:
17951b08e436SShashi Mallela         result = false;
17961b08e436SShashi Mallela         break;
17971b08e436SShashi Mallela     }
179818f6290aSShashi Mallela     return result;
179918f6290aSShashi Mallela }
180018f6290aSShashi Mallela 
its_readll(GICv3ITSState * s,hwaddr offset,uint64_t * data,MemTxAttrs attrs)180118f6290aSShashi Mallela static bool its_readll(GICv3ITSState *s, hwaddr offset,
180218f6290aSShashi Mallela                               uint64_t *data, MemTxAttrs attrs)
180318f6290aSShashi Mallela {
180418f6290aSShashi Mallela     bool result = true;
18051b08e436SShashi Mallela     int index;
180618f6290aSShashi Mallela 
18071b08e436SShashi Mallela     switch (offset) {
18081b08e436SShashi Mallela     case GITS_TYPER:
18091b08e436SShashi Mallela         *data = s->typer;
18101b08e436SShashi Mallela         break;
18111b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
18121b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
18131b08e436SShashi Mallela         *data = s->baser[index];
18141b08e436SShashi Mallela         break;
18151b08e436SShashi Mallela     case GITS_CBASER:
18161b08e436SShashi Mallela         *data = s->cbaser;
18171b08e436SShashi Mallela         break;
18181b08e436SShashi Mallela     case GITS_CREADR:
18191b08e436SShashi Mallela         *data = s->creadr;
18201b08e436SShashi Mallela         break;
18211b08e436SShashi Mallela     case GITS_CWRITER:
18221b08e436SShashi Mallela         *data = s->cwriter;
18231b08e436SShashi Mallela         break;
18241b08e436SShashi Mallela     default:
18251b08e436SShashi Mallela         result = false;
18261b08e436SShashi Mallela         break;
18271b08e436SShashi Mallela     }
182818f6290aSShashi Mallela     return result;
182918f6290aSShashi Mallela }
183018f6290aSShashi Mallela 
gicv3_its_read(void * opaque,hwaddr offset,uint64_t * data,unsigned size,MemTxAttrs attrs)183118f6290aSShashi Mallela static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
183218f6290aSShashi Mallela                                   unsigned size, MemTxAttrs attrs)
183318f6290aSShashi Mallela {
183418f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
183518f6290aSShashi Mallela     bool result;
183618f6290aSShashi Mallela 
183718f6290aSShashi Mallela     switch (size) {
183818f6290aSShashi Mallela     case 4:
183918f6290aSShashi Mallela         result = its_readl(s, offset, data, attrs);
184018f6290aSShashi Mallela         break;
184118f6290aSShashi Mallela     case 8:
184218f6290aSShashi Mallela         result = its_readll(s, offset, data, attrs);
184318f6290aSShashi Mallela         break;
184418f6290aSShashi Mallela     default:
184518f6290aSShashi Mallela         result = false;
184618f6290aSShashi Mallela         break;
184718f6290aSShashi Mallela     }
184818f6290aSShashi Mallela 
184918f6290aSShashi Mallela     if (!result) {
185018f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
1851883f2c59SPhilippe Mathieu-Daudé                       "%s: invalid guest read at offset " HWADDR_FMT_plx
185218f6290aSShashi Mallela                       " size %u\n", __func__, offset, size);
1853195209d3SPeter Maydell         trace_gicv3_its_badread(offset, size);
185418f6290aSShashi Mallela         /*
185518f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
185618f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
185718f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
185818f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
185918f6290aSShashi Mallela          */
186018f6290aSShashi Mallela         *data = 0;
1861195209d3SPeter Maydell     } else {
1862195209d3SPeter Maydell         trace_gicv3_its_read(offset, *data, size);
186318f6290aSShashi Mallela     }
186418f6290aSShashi Mallela     return MEMTX_OK;
186518f6290aSShashi Mallela }
186618f6290aSShashi Mallela 
gicv3_its_write(void * opaque,hwaddr offset,uint64_t data,unsigned size,MemTxAttrs attrs)186718f6290aSShashi Mallela static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
186818f6290aSShashi Mallela                                    unsigned size, MemTxAttrs attrs)
186918f6290aSShashi Mallela {
187018f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
187118f6290aSShashi Mallela     bool result;
187218f6290aSShashi Mallela 
187318f6290aSShashi Mallela     switch (size) {
187418f6290aSShashi Mallela     case 4:
187518f6290aSShashi Mallela         result = its_writel(s, offset, data, attrs);
187618f6290aSShashi Mallela         break;
187718f6290aSShashi Mallela     case 8:
187818f6290aSShashi Mallela         result = its_writell(s, offset, data, attrs);
187918f6290aSShashi Mallela         break;
188018f6290aSShashi Mallela     default:
188118f6290aSShashi Mallela         result = false;
188218f6290aSShashi Mallela         break;
188318f6290aSShashi Mallela     }
188418f6290aSShashi Mallela 
188518f6290aSShashi Mallela     if (!result) {
188618f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
1887883f2c59SPhilippe Mathieu-Daudé                       "%s: invalid guest write at offset " HWADDR_FMT_plx
188818f6290aSShashi Mallela                       " size %u\n", __func__, offset, size);
1889195209d3SPeter Maydell         trace_gicv3_its_badwrite(offset, data, size);
189018f6290aSShashi Mallela         /*
189118f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
189218f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
189318f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
189418f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
189518f6290aSShashi Mallela          */
1896195209d3SPeter Maydell     } else {
1897195209d3SPeter Maydell         trace_gicv3_its_write(offset, data, size);
189818f6290aSShashi Mallela     }
189918f6290aSShashi Mallela     return MEMTX_OK;
190018f6290aSShashi Mallela }
190118f6290aSShashi Mallela 
190218f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_control_ops = {
190318f6290aSShashi Mallela     .read_with_attrs = gicv3_its_read,
190418f6290aSShashi Mallela     .write_with_attrs = gicv3_its_write,
190518f6290aSShashi Mallela     .valid.min_access_size = 4,
190618f6290aSShashi Mallela     .valid.max_access_size = 8,
190718f6290aSShashi Mallela     .impl.min_access_size = 4,
190818f6290aSShashi Mallela     .impl.max_access_size = 8,
190918f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
191018f6290aSShashi Mallela };
191118f6290aSShashi Mallela 
191218f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_translation_ops = {
19137e062b98SPeter Maydell     .read_with_attrs = gicv3_its_translation_read,
191418f6290aSShashi Mallela     .write_with_attrs = gicv3_its_translation_write,
191518f6290aSShashi Mallela     .valid.min_access_size = 2,
191618f6290aSShashi Mallela     .valid.max_access_size = 4,
191718f6290aSShashi Mallela     .impl.min_access_size = 2,
191818f6290aSShashi Mallela     .impl.max_access_size = 4,
191918f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
192018f6290aSShashi Mallela };
192118f6290aSShashi Mallela 
gicv3_arm_its_realize(DeviceState * dev,Error ** errp)192218f6290aSShashi Mallela static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
192318f6290aSShashi Mallela {
192418f6290aSShashi Mallela     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
192518f6290aSShashi Mallela     int i;
192618f6290aSShashi Mallela 
192718f6290aSShashi Mallela     for (i = 0; i < s->gicv3->num_cpu; i++) {
192818f6290aSShashi Mallela         if (!(s->gicv3->cpu[i].gicr_typer & GICR_TYPER_PLPIS)) {
192918f6290aSShashi Mallela             error_setg(errp, "Physical LPI not supported by CPU %d", i);
193018f6290aSShashi Mallela             return;
193118f6290aSShashi Mallela         }
193218f6290aSShashi Mallela     }
193318f6290aSShashi Mallela 
19347c087bd3SPeter Maydell     gicv3_add_its(s->gicv3, dev);
19357c087bd3SPeter Maydell 
193618f6290aSShashi Mallela     gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops);
193718f6290aSShashi Mallela 
193818f6290aSShashi Mallela     /* set the ITS default features supported */
1939764d6ba1SPeter Maydell     s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL, 1);
194018f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, ITT_ENTRY_SIZE,
194118f6290aSShashi Mallela                           ITS_ITT_ENTRY_SIZE - 1);
194218f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, IDBITS, ITS_IDBITS);
194318f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, DEVBITS, ITS_DEVBITS);
194418f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIL, 1);
194518f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIDBITS, ITS_CIDBITS);
1946e2d5e189SPeter Maydell     if (s->gicv3->revision >= 4) {
1947e2d5e189SPeter Maydell         /* Our VMOVP handles cross-ITS synchronization itself */
1948e2d5e189SPeter Maydell         s->typer = FIELD_DP64(s->typer, GITS_TYPER, VMOVP, 1);
1949e2d5e189SPeter Maydell         s->typer = FIELD_DP64(s->typer, GITS_TYPER, VIRTUAL, 1);
1950e2d5e189SPeter Maydell     }
195118f6290aSShashi Mallela }
195218f6290aSShashi Mallela 
gicv3_its_reset_hold(Object * obj,ResetType type)1953ad80e367SPeter Maydell static void gicv3_its_reset_hold(Object *obj, ResetType type)
195418f6290aSShashi Mallela {
19551bcb9076SPeter Maydell     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(obj);
195618f6290aSShashi Mallela     GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s);
195718f6290aSShashi Mallela 
19581bcb9076SPeter Maydell     if (c->parent_phases.hold) {
1959ad80e367SPeter Maydell         c->parent_phases.hold(obj, type);
19601bcb9076SPeter Maydell     }
196118f6290aSShashi Mallela 
196218f6290aSShashi Mallela     /* Quiescent bit reset to 1 */
196318f6290aSShashi Mallela     s->ctlr = FIELD_DP32(s->ctlr, GITS_CTLR, QUIESCENT, 1);
196418f6290aSShashi Mallela 
196518f6290aSShashi Mallela     /*
196618f6290aSShashi Mallela      * setting GITS_BASER0.Type = 0b001 (Device)
196718f6290aSShashi Mallela      *         GITS_BASER1.Type = 0b100 (Collection Table)
196850d84584SPeter Maydell      *         GITS_BASER2.Type = 0b010 (vPE) for GICv4 and later
196918f6290aSShashi Mallela      *         GITS_BASER<n>.Type,where n = 3 to 7 are 0b00 (Unimplemented)
197018f6290aSShashi Mallela      *         GITS_BASER<0,1>.Page_Size = 64KB
197118f6290aSShashi Mallela      * and default translation table entry size to 16 bytes
197218f6290aSShashi Mallela      */
197318f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, TYPE,
197418f6290aSShashi Mallela                              GITS_BASER_TYPE_DEVICE);
197518f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, PAGESIZE,
197618f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
197718f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, ENTRYSIZE,
197818f6290aSShashi Mallela                              GITS_DTE_SIZE - 1);
197918f6290aSShashi Mallela 
198018f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, TYPE,
198118f6290aSShashi Mallela                              GITS_BASER_TYPE_COLLECTION);
198218f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, PAGESIZE,
198318f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
198418f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, ENTRYSIZE,
198518f6290aSShashi Mallela                              GITS_CTE_SIZE - 1);
198650d84584SPeter Maydell 
198750d84584SPeter Maydell     if (its_feature_virtual(s)) {
198850d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, TYPE,
198950d84584SPeter Maydell                                  GITS_BASER_TYPE_VPE);
199050d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, PAGESIZE,
199150d84584SPeter Maydell                                  GITS_BASER_PAGESIZE_64K);
199250d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, ENTRYSIZE,
199350d84584SPeter Maydell                                  GITS_VPE_SIZE - 1);
199450d84584SPeter Maydell     }
199518f6290aSShashi Mallela }
199618f6290aSShashi Mallela 
gicv3_its_post_load(GICv3ITSState * s)19971b08e436SShashi Mallela static void gicv3_its_post_load(GICv3ITSState *s)
19981b08e436SShashi Mallela {
19998d2d6dd9SPeter Maydell     if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
20001b08e436SShashi Mallela         extract_table_params(s);
20011b08e436SShashi Mallela         extract_cmdq_params(s);
20021b08e436SShashi Mallela     }
20031b08e436SShashi Mallela }
20041b08e436SShashi Mallela 
2005783e3b21SRichard Henderson static const Property gicv3_its_props[] = {
200618f6290aSShashi Mallela     DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3",
200718f6290aSShashi Mallela                      GICv3State *),
200818f6290aSShashi Mallela };
200918f6290aSShashi Mallela 
gicv3_its_class_init(ObjectClass * klass,const void * data)2010*12d1a768SPhilippe Mathieu-Daudé static void gicv3_its_class_init(ObjectClass *klass, const void *data)
201118f6290aSShashi Mallela {
201218f6290aSShashi Mallela     DeviceClass *dc = DEVICE_CLASS(klass);
20131bcb9076SPeter Maydell     ResettableClass *rc = RESETTABLE_CLASS(klass);
201418f6290aSShashi Mallela     GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass);
20151b08e436SShashi Mallela     GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
201618f6290aSShashi Mallela 
201718f6290aSShashi Mallela     dc->realize = gicv3_arm_its_realize;
201818f6290aSShashi Mallela     device_class_set_props(dc, gicv3_its_props);
20191bcb9076SPeter Maydell     resettable_class_set_parent_phases(rc, NULL, gicv3_its_reset_hold, NULL,
20201bcb9076SPeter Maydell                                        &ic->parent_phases);
20211b08e436SShashi Mallela     icc->post_load = gicv3_its_post_load;
202218f6290aSShashi Mallela }
202318f6290aSShashi Mallela 
202418f6290aSShashi Mallela static const TypeInfo gicv3_its_info = {
202518f6290aSShashi Mallela     .name = TYPE_ARM_GICV3_ITS,
202618f6290aSShashi Mallela     .parent = TYPE_ARM_GICV3_ITS_COMMON,
202718f6290aSShashi Mallela     .instance_size = sizeof(GICv3ITSState),
202818f6290aSShashi Mallela     .class_init = gicv3_its_class_init,
202918f6290aSShashi Mallela     .class_size = sizeof(GICv3ITSClass),
203018f6290aSShashi Mallela };
203118f6290aSShashi Mallela 
gicv3_its_register_types(void)203218f6290aSShashi Mallela static void gicv3_its_register_types(void)
203318f6290aSShashi Mallela {
203418f6290aSShashi Mallela     type_register_static(&gicv3_its_info);
203518f6290aSShashi Mallela }
203618f6290aSShashi Mallela 
203718f6290aSShashi Mallela type_init(gicv3_its_register_types)
2038