xref: /qemu/hw/intc/arm_gicv3_its.c (revision 93f4fdcd4d98c0de8e056e08016bce7d71a91100)
118f6290aSShashi Mallela /*
218f6290aSShashi Mallela  * ITS emulation for a GICv3-based system
318f6290aSShashi Mallela  *
418f6290aSShashi Mallela  * Copyright Linaro.org 2021
518f6290aSShashi Mallela  *
618f6290aSShashi Mallela  * Authors:
718f6290aSShashi Mallela  *  Shashi Mallela <shashi.mallela@linaro.org>
818f6290aSShashi Mallela  *
918f6290aSShashi Mallela  * This work is licensed under the terms of the GNU GPL, version 2 or (at your
1018f6290aSShashi Mallela  * option) any later version.  See the COPYING file in the top-level directory.
1118f6290aSShashi Mallela  *
1218f6290aSShashi Mallela  */
1318f6290aSShashi Mallela 
1418f6290aSShashi Mallela #include "qemu/osdep.h"
1518f6290aSShashi Mallela #include "qemu/log.h"
16195209d3SPeter Maydell #include "trace.h"
1718f6290aSShashi Mallela #include "hw/qdev-properties.h"
1818f6290aSShashi Mallela #include "hw/intc/arm_gicv3_its_common.h"
1918f6290aSShashi Mallela #include "gicv3_internal.h"
2018f6290aSShashi Mallela #include "qom/object.h"
2118f6290aSShashi Mallela #include "qapi/error.h"
2218f6290aSShashi Mallela 
2318f6290aSShashi Mallela typedef struct GICv3ITSClass GICv3ITSClass;
2418f6290aSShashi Mallela /* This is reusing the GICv3ITSState typedef from ARM_GICV3_ITS_COMMON */
2518f6290aSShashi Mallela DECLARE_OBJ_CHECKERS(GICv3ITSState, GICv3ITSClass,
2618f6290aSShashi Mallela                      ARM_GICV3_ITS, TYPE_ARM_GICV3_ITS)
2718f6290aSShashi Mallela 
2818f6290aSShashi Mallela struct GICv3ITSClass {
2918f6290aSShashi Mallela     GICv3ITSCommonClass parent_class;
3018f6290aSShashi Mallela     void (*parent_reset)(DeviceState *dev);
3118f6290aSShashi Mallela };
3218f6290aSShashi Mallela 
33c694cb4cSShashi Mallela /*
34c694cb4cSShashi Mallela  * This is an internal enum used to distinguish between LPI triggered
35c694cb4cSShashi Mallela  * via command queue and LPI triggered via gits_translater write.
36c694cb4cSShashi Mallela  */
37c694cb4cSShashi Mallela typedef enum ItsCmdType {
38c694cb4cSShashi Mallela     NONE = 0, /* internal indication for GITS_TRANSLATER write */
39c694cb4cSShashi Mallela     CLEAR = 1,
40c694cb4cSShashi Mallela     DISCARD = 2,
41c694cb4cSShashi Mallela     INTERRUPT = 3,
42c694cb4cSShashi Mallela } ItsCmdType;
43c694cb4cSShashi Mallela 
444acf93e1SPeter Maydell typedef struct DTEntry {
454acf93e1SPeter Maydell     bool valid;
464acf93e1SPeter Maydell     unsigned size;
474acf93e1SPeter Maydell     uint64_t ittaddr;
484acf93e1SPeter Maydell } DTEntry;
494acf93e1SPeter Maydell 
50d37cf49bSPeter Maydell typedef struct CTEntry {
51d37cf49bSPeter Maydell     bool valid;
52d37cf49bSPeter Maydell     uint32_t rdbase;
53d37cf49bSPeter Maydell } CTEntry;
54d37cf49bSPeter Maydell 
55244194feSPeter Maydell typedef struct ITEntry {
56244194feSPeter Maydell     bool valid;
57244194feSPeter Maydell     int inttype;
58244194feSPeter Maydell     uint32_t intid;
59244194feSPeter Maydell     uint32_t doorbell;
60244194feSPeter Maydell     uint32_t icid;
61244194feSPeter Maydell     uint32_t vpeid;
62244194feSPeter Maydell } ITEntry;
63244194feSPeter Maydell 
640cdf7a5dSPeter Maydell typedef struct VTEntry {
650cdf7a5dSPeter Maydell     bool valid;
660cdf7a5dSPeter Maydell     unsigned vptsize;
670cdf7a5dSPeter Maydell     uint32_t rdbase;
680cdf7a5dSPeter Maydell     uint64_t vptaddr;
690cdf7a5dSPeter Maydell } VTEntry;
70244194feSPeter Maydell 
71ef011555SPeter Maydell /*
72ef011555SPeter Maydell  * The ITS spec permits a range of CONSTRAINED UNPREDICTABLE options
73ef011555SPeter Maydell  * if a command parameter is not correct. These include both "stall
74ef011555SPeter Maydell  * processing of the command queue" and "ignore this command, and
75ef011555SPeter Maydell  * keep processing the queue". In our implementation we choose that
76ef011555SPeter Maydell  * memory transaction errors reading the command packet provoke a
77ef011555SPeter Maydell  * stall, but errors in parameters cause us to ignore the command
78ef011555SPeter Maydell  * and continue processing.
79ef011555SPeter Maydell  * The process_* functions which handle individual ITS commands all
80ef011555SPeter Maydell  * return an ItsCmdResult which tells process_cmdq() whether it should
81*93f4fdcdSPeter Maydell  * stall, keep going because of an error, or keep going because the
82*93f4fdcdSPeter Maydell  * command was a success.
83ef011555SPeter Maydell  */
84ef011555SPeter Maydell typedef enum ItsCmdResult {
85ef011555SPeter Maydell     CMD_STALL = 0,
86ef011555SPeter Maydell     CMD_CONTINUE = 1,
87*93f4fdcdSPeter Maydell     CMD_CONTINUE_OK = 2,
88ef011555SPeter Maydell } ItsCmdResult;
89ef011555SPeter Maydell 
9050d84584SPeter Maydell /* True if the ITS supports the GICv4 virtual LPI feature */
9150d84584SPeter Maydell static bool its_feature_virtual(GICv3ITSState *s)
9250d84584SPeter Maydell {
9350d84584SPeter Maydell     return s->typer & R_GITS_TYPER_VIRTUAL_MASK;
9450d84584SPeter Maydell }
9550d84584SPeter Maydell 
96c3c9a090SPeter Maydell static inline bool intid_in_lpi_range(uint32_t id)
97c3c9a090SPeter Maydell {
98c3c9a090SPeter Maydell     return id >= GICV3_LPI_INTID_START &&
99c3c9a090SPeter Maydell         id < (1 << (GICD_TYPER_IDBITS + 1));
100c3c9a090SPeter Maydell }
101c3c9a090SPeter Maydell 
1029de53de6SPeter Maydell static inline bool valid_doorbell(uint32_t id)
1039de53de6SPeter Maydell {
1049de53de6SPeter Maydell     /* Doorbell fields may be an LPI, or 1023 to mean "no doorbell" */
1059de53de6SPeter Maydell     return id == INTID_SPURIOUS || intid_in_lpi_range(id);
1069de53de6SPeter Maydell }
1079de53de6SPeter Maydell 
1081b08e436SShashi Mallela static uint64_t baser_base_addr(uint64_t value, uint32_t page_sz)
1091b08e436SShashi Mallela {
1101b08e436SShashi Mallela     uint64_t result = 0;
1111b08e436SShashi Mallela 
1121b08e436SShashi Mallela     switch (page_sz) {
1131b08e436SShashi Mallela     case GITS_PAGE_SIZE_4K:
1141b08e436SShashi Mallela     case GITS_PAGE_SIZE_16K:
1151b08e436SShashi Mallela         result = FIELD_EX64(value, GITS_BASER, PHYADDR) << 12;
1161b08e436SShashi Mallela         break;
1171b08e436SShashi Mallela 
1181b08e436SShashi Mallela     case GITS_PAGE_SIZE_64K:
1191b08e436SShashi Mallela         result = FIELD_EX64(value, GITS_BASER, PHYADDRL_64K) << 16;
1201b08e436SShashi Mallela         result |= FIELD_EX64(value, GITS_BASER, PHYADDRH_64K) << 48;
1211b08e436SShashi Mallela         break;
1221b08e436SShashi Mallela 
1231b08e436SShashi Mallela     default:
1241b08e436SShashi Mallela         break;
1251b08e436SShashi Mallela     }
1261b08e436SShashi Mallela     return result;
1271b08e436SShashi Mallela }
1281b08e436SShashi Mallela 
129d050f80fSPeter Maydell static uint64_t table_entry_addr(GICv3ITSState *s, TableDesc *td,
130d050f80fSPeter Maydell                                  uint32_t idx, MemTxResult *res)
131d050f80fSPeter Maydell {
132d050f80fSPeter Maydell     /*
133d050f80fSPeter Maydell      * Given a TableDesc describing one of the ITS in-guest-memory
134d050f80fSPeter Maydell      * tables and an index into it, return the guest address
135d050f80fSPeter Maydell      * corresponding to that table entry.
136d050f80fSPeter Maydell      * If there was a memory error reading the L1 table of an
137d050f80fSPeter Maydell      * indirect table, *res is set accordingly, and we return -1.
138d050f80fSPeter Maydell      * If the L1 table entry is marked not valid, we return -1 with
139d050f80fSPeter Maydell      * *res set to MEMTX_OK.
140d050f80fSPeter Maydell      *
141d050f80fSPeter Maydell      * The specification defines the format of level 1 entries of a
142d050f80fSPeter Maydell      * 2-level table, but the format of level 2 entries and the format
143d050f80fSPeter Maydell      * of flat-mapped tables is IMPDEF.
144d050f80fSPeter Maydell      */
145d050f80fSPeter Maydell     AddressSpace *as = &s->gicv3->dma_as;
146d050f80fSPeter Maydell     uint32_t l2idx;
147d050f80fSPeter Maydell     uint64_t l2;
148d050f80fSPeter Maydell     uint32_t num_l2_entries;
149d050f80fSPeter Maydell 
150d050f80fSPeter Maydell     *res = MEMTX_OK;
151d050f80fSPeter Maydell 
152d050f80fSPeter Maydell     if (!td->indirect) {
153d050f80fSPeter Maydell         /* Single level table */
154d050f80fSPeter Maydell         return td->base_addr + idx * td->entry_sz;
155d050f80fSPeter Maydell     }
156d050f80fSPeter Maydell 
157d050f80fSPeter Maydell     /* Two level table */
158d050f80fSPeter Maydell     l2idx = idx / (td->page_sz / L1TABLE_ENTRY_SIZE);
159d050f80fSPeter Maydell 
160d050f80fSPeter Maydell     l2 = address_space_ldq_le(as,
161d050f80fSPeter Maydell                               td->base_addr + (l2idx * L1TABLE_ENTRY_SIZE),
162d050f80fSPeter Maydell                               MEMTXATTRS_UNSPECIFIED, res);
163d050f80fSPeter Maydell     if (*res != MEMTX_OK) {
164d050f80fSPeter Maydell         return -1;
165d050f80fSPeter Maydell     }
166d050f80fSPeter Maydell     if (!(l2 & L2_TABLE_VALID_MASK)) {
167d050f80fSPeter Maydell         return -1;
168d050f80fSPeter Maydell     }
169d050f80fSPeter Maydell 
170d050f80fSPeter Maydell     num_l2_entries = td->page_sz / td->entry_sz;
171d050f80fSPeter Maydell     return (l2 & ((1ULL << 51) - 1)) + (idx % num_l2_entries) * td->entry_sz;
172d050f80fSPeter Maydell }
173d050f80fSPeter Maydell 
174d37cf49bSPeter Maydell /*
175d37cf49bSPeter Maydell  * Read the Collection Table entry at index @icid. On success (including
176d37cf49bSPeter Maydell  * successfully determining that there is no valid CTE for this index),
177d37cf49bSPeter Maydell  * we return MEMTX_OK and populate the CTEntry struct @cte accordingly.
178d37cf49bSPeter Maydell  * If there is an error reading memory then we return the error code.
179d37cf49bSPeter Maydell  */
180d37cf49bSPeter Maydell static MemTxResult get_cte(GICv3ITSState *s, uint16_t icid, CTEntry *cte)
181c694cb4cSShashi Mallela {
182c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
183d37cf49bSPeter Maydell     MemTxResult res = MEMTX_OK;
184d37cf49bSPeter Maydell     uint64_t entry_addr = table_entry_addr(s, &s->ct, icid, &res);
185d37cf49bSPeter Maydell     uint64_t cteval;
186c694cb4cSShashi Mallela 
187d050f80fSPeter Maydell     if (entry_addr == -1) {
188d37cf49bSPeter Maydell         /* No L2 table entry, i.e. no valid CTE, or a memory error */
189d37cf49bSPeter Maydell         cte->valid = false;
190930f40e9SPeter Maydell         goto out;
191c694cb4cSShashi Mallela     }
192c694cb4cSShashi Mallela 
193d37cf49bSPeter Maydell     cteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res);
194d37cf49bSPeter Maydell     if (res != MEMTX_OK) {
195930f40e9SPeter Maydell         goto out;
196d37cf49bSPeter Maydell     }
197d37cf49bSPeter Maydell     cte->valid = FIELD_EX64(cteval, CTE, VALID);
198d37cf49bSPeter Maydell     cte->rdbase = FIELD_EX64(cteval, CTE, RDBASE);
199930f40e9SPeter Maydell out:
200930f40e9SPeter Maydell     if (res != MEMTX_OK) {
201930f40e9SPeter Maydell         trace_gicv3_its_cte_read_fault(icid);
202930f40e9SPeter Maydell     } else {
203930f40e9SPeter Maydell         trace_gicv3_its_cte_read(icid, cte->valid, cte->rdbase);
204930f40e9SPeter Maydell     }
205930f40e9SPeter Maydell     return res;
206c694cb4cSShashi Mallela }
207c694cb4cSShashi Mallela 
2087eb54267SPeter Maydell /*
2097eb54267SPeter Maydell  * Update the Interrupt Table entry at index @evinted in the table specified
2107eb54267SPeter Maydell  * by the dte @dte. Returns true on success, false if there was a memory
2117eb54267SPeter Maydell  * access error.
2127eb54267SPeter Maydell  */
2134acf93e1SPeter Maydell static bool update_ite(GICv3ITSState *s, uint32_t eventid, const DTEntry *dte,
2147eb54267SPeter Maydell                        const ITEntry *ite)
215c694cb4cSShashi Mallela {
216c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
217c694cb4cSShashi Mallela     MemTxResult res = MEMTX_OK;
218a1ce993dSPeter Maydell     hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
2197eb54267SPeter Maydell     uint64_t itel = 0;
2207eb54267SPeter Maydell     uint32_t iteh = 0;
221c694cb4cSShashi Mallela 
222930f40e9SPeter Maydell     trace_gicv3_its_ite_write(dte->ittaddr, eventid, ite->valid,
223930f40e9SPeter Maydell                               ite->inttype, ite->intid, ite->icid,
224930f40e9SPeter Maydell                               ite->vpeid, ite->doorbell);
225930f40e9SPeter Maydell 
2267eb54267SPeter Maydell     if (ite->valid) {
2277eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, VALID, 1);
2287eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, INTTYPE, ite->inttype);
2297eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, INTID, ite->intid);
2307eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, ICID, ite->icid);
2317eb54267SPeter Maydell         itel = FIELD_DP64(itel, ITE_L, VPEID, ite->vpeid);
2327eb54267SPeter Maydell         iteh = FIELD_DP32(iteh, ITE_H, DOORBELL, ite->doorbell);
233c694cb4cSShashi Mallela     }
2347eb54267SPeter Maydell 
2357eb54267SPeter Maydell     address_space_stq_le(as, iteaddr, itel, MEMTXATTRS_UNSPECIFIED, &res);
236c694cb4cSShashi Mallela     if (res != MEMTX_OK) {
237c694cb4cSShashi Mallela         return false;
238c694cb4cSShashi Mallela     }
2397eb54267SPeter Maydell     address_space_stl_le(as, iteaddr + 8, iteh, MEMTXATTRS_UNSPECIFIED, &res);
2407eb54267SPeter Maydell     return res == MEMTX_OK;
241c694cb4cSShashi Mallela }
242c694cb4cSShashi Mallela 
243244194feSPeter Maydell /*
244244194feSPeter Maydell  * Read the Interrupt Table entry at index @eventid from the table specified
245244194feSPeter Maydell  * by the DTE @dte. On success, we return MEMTX_OK and populate the ITEntry
246244194feSPeter Maydell  * struct @ite accordingly. If there is an error reading memory then we return
247244194feSPeter Maydell  * the error code.
248244194feSPeter Maydell  */
249244194feSPeter Maydell static MemTxResult get_ite(GICv3ITSState *s, uint32_t eventid,
250244194feSPeter Maydell                            const DTEntry *dte, ITEntry *ite)
251c694cb4cSShashi Mallela {
252c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
253244194feSPeter Maydell     MemTxResult res = MEMTX_OK;
254244194feSPeter Maydell     uint64_t itel;
255244194feSPeter Maydell     uint32_t iteh;
256a1ce993dSPeter Maydell     hwaddr iteaddr = dte->ittaddr + eventid * ITS_ITT_ENTRY_SIZE;
257c694cb4cSShashi Mallela 
258244194feSPeter Maydell     itel = address_space_ldq_le(as, iteaddr, MEMTXATTRS_UNSPECIFIED, &res);
259244194feSPeter Maydell     if (res != MEMTX_OK) {
260930f40e9SPeter Maydell         trace_gicv3_its_ite_read_fault(dte->ittaddr, eventid);
261244194feSPeter Maydell         return res;
2622954b93fSPeter Maydell     }
263c694cb4cSShashi Mallela 
264244194feSPeter Maydell     iteh = address_space_ldl_le(as, iteaddr + 8, MEMTXATTRS_UNSPECIFIED, &res);
265244194feSPeter Maydell     if (res != MEMTX_OK) {
266930f40e9SPeter Maydell         trace_gicv3_its_ite_read_fault(dte->ittaddr, eventid);
267244194feSPeter Maydell         return res;
2682954b93fSPeter Maydell     }
269c694cb4cSShashi Mallela 
270244194feSPeter Maydell     ite->valid = FIELD_EX64(itel, ITE_L, VALID);
271244194feSPeter Maydell     ite->inttype = FIELD_EX64(itel, ITE_L, INTTYPE);
272244194feSPeter Maydell     ite->intid = FIELD_EX64(itel, ITE_L, INTID);
273244194feSPeter Maydell     ite->icid = FIELD_EX64(itel, ITE_L, ICID);
274244194feSPeter Maydell     ite->vpeid = FIELD_EX64(itel, ITE_L, VPEID);
275244194feSPeter Maydell     ite->doorbell = FIELD_EX64(iteh, ITE_H, DOORBELL);
276930f40e9SPeter Maydell     trace_gicv3_its_ite_read(dte->ittaddr, eventid, ite->valid,
277930f40e9SPeter Maydell                              ite->inttype, ite->intid, ite->icid,
278930f40e9SPeter Maydell                              ite->vpeid, ite->doorbell);
279244194feSPeter Maydell     return MEMTX_OK;
280c694cb4cSShashi Mallela }
281c694cb4cSShashi Mallela 
2824acf93e1SPeter Maydell /*
2834acf93e1SPeter Maydell  * Read the Device Table entry at index @devid. On success (including
2844acf93e1SPeter Maydell  * successfully determining that there is no valid DTE for this index),
2854acf93e1SPeter Maydell  * we return MEMTX_OK and populate the DTEntry struct accordingly.
2864acf93e1SPeter Maydell  * If there is an error reading memory then we return the error code.
2874acf93e1SPeter Maydell  */
2884acf93e1SPeter Maydell static MemTxResult get_dte(GICv3ITSState *s, uint32_t devid, DTEntry *dte)
289c694cb4cSShashi Mallela {
2904acf93e1SPeter Maydell     MemTxResult res = MEMTX_OK;
291c694cb4cSShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
2924acf93e1SPeter Maydell     uint64_t entry_addr = table_entry_addr(s, &s->dt, devid, &res);
2934acf93e1SPeter Maydell     uint64_t dteval;
294c694cb4cSShashi Mallela 
295d050f80fSPeter Maydell     if (entry_addr == -1) {
2964acf93e1SPeter Maydell         /* No L2 table entry, i.e. no valid DTE, or a memory error */
2974acf93e1SPeter Maydell         dte->valid = false;
298930f40e9SPeter Maydell         goto out;
299c694cb4cSShashi Mallela     }
3004acf93e1SPeter Maydell     dteval = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, &res);
3014acf93e1SPeter Maydell     if (res != MEMTX_OK) {
302930f40e9SPeter Maydell         goto out;
3034acf93e1SPeter Maydell     }
3044acf93e1SPeter Maydell     dte->valid = FIELD_EX64(dteval, DTE, VALID);
3054acf93e1SPeter Maydell     dte->size = FIELD_EX64(dteval, DTE, SIZE);
3064acf93e1SPeter Maydell     /* DTE word field stores bits [51:8] of the ITT address */
3074acf93e1SPeter Maydell     dte->ittaddr = FIELD_EX64(dteval, DTE, ITTADDR) << ITTADDR_SHIFT;
308930f40e9SPeter Maydell out:
309930f40e9SPeter Maydell     if (res != MEMTX_OK) {
310930f40e9SPeter Maydell         trace_gicv3_its_dte_read_fault(devid);
311930f40e9SPeter Maydell     } else {
312930f40e9SPeter Maydell         trace_gicv3_its_dte_read(devid, dte->valid, dte->size, dte->ittaddr);
313930f40e9SPeter Maydell     }
314930f40e9SPeter Maydell     return res;
315c694cb4cSShashi Mallela }
316c694cb4cSShashi Mallela 
317c694cb4cSShashi Mallela /*
318c694cb4cSShashi Mallela  * This function handles the processing of following commands based on
319c694cb4cSShashi Mallela  * the ItsCmdType parameter passed:-
320c694cb4cSShashi Mallela  * 1. triggering of lpi interrupt translation via ITS INT command
321c694cb4cSShashi Mallela  * 2. triggering of lpi interrupt translation via gits_translater register
322c694cb4cSShashi Mallela  * 3. handling of ITS CLEAR command
323c694cb4cSShashi Mallela  * 4. handling of ITS DISCARD command
324c694cb4cSShashi Mallela  */
325b6f96009SPeter Maydell static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid,
326b6f96009SPeter Maydell                                        uint32_t eventid, ItsCmdType cmd)
327c694cb4cSShashi Mallela {
3288f809f69SPeter Maydell     uint64_t num_eventids;
3294acf93e1SPeter Maydell     DTEntry dte;
330d37cf49bSPeter Maydell     CTEntry cte;
331244194feSPeter Maydell     ITEntry ite;
332c694cb4cSShashi Mallela 
3338b8bb014SPeter Maydell     if (devid >= s->dt.num_entries) {
334b13148d9SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
335b13148d9SPeter Maydell                       "%s: invalid command attributes: devid %d>=%d",
3368b8bb014SPeter Maydell                       __func__, devid, s->dt.num_entries);
337b13148d9SPeter Maydell         return CMD_CONTINUE;
338b13148d9SPeter Maydell     }
339b13148d9SPeter Maydell 
3404acf93e1SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
341593a7cc2SPeter Maydell         return CMD_STALL;
342c694cb4cSShashi Mallela     }
3434acf93e1SPeter Maydell     if (!dte.valid) {
344229c57b1SAlex Bennée         qemu_log_mask(LOG_GUEST_ERROR,
345229c57b1SAlex Bennée                       "%s: invalid command attributes: "
3464acf93e1SPeter Maydell                       "invalid dte for %d\n", __func__, devid);
347593a7cc2SPeter Maydell         return CMD_CONTINUE;
348c694cb4cSShashi Mallela     }
349c694cb4cSShashi Mallela 
3504acf93e1SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
351b13148d9SPeter Maydell     if (eventid >= num_eventids) {
352b13148d9SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
353b13148d9SPeter Maydell                       "%s: invalid command attributes: eventid %d >= %"
354b13148d9SPeter Maydell                       PRId64 "\n",
355b13148d9SPeter Maydell                       __func__, eventid, num_eventids);
356b13148d9SPeter Maydell         return CMD_CONTINUE;
357b13148d9SPeter Maydell     }
358b13148d9SPeter Maydell 
359244194feSPeter Maydell     if (get_ite(s, eventid, &dte, &ite) != MEMTX_OK) {
360be0ed8fbSPeter Maydell         return CMD_STALL;
361be0ed8fbSPeter Maydell     }
362be0ed8fbSPeter Maydell 
363244194feSPeter Maydell     if (!ite.valid || ite.inttype != ITE_INTTYPE_PHYSICAL) {
364be0ed8fbSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
365be0ed8fbSPeter Maydell                       "%s: invalid command attributes: invalid ITE\n",
366be0ed8fbSPeter Maydell                       __func__);
367be0ed8fbSPeter Maydell         return CMD_CONTINUE;
368be0ed8fbSPeter Maydell     }
369be0ed8fbSPeter Maydell 
370244194feSPeter Maydell     if (ite.icid >= s->ct.num_entries) {
37158b88779SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
37258b88779SPeter Maydell                       "%s: invalid ICID 0x%x in ITE (table corrupted?)\n",
373244194feSPeter Maydell                       __func__, ite.icid);
37458b88779SPeter Maydell         return CMD_CONTINUE;
37558b88779SPeter Maydell     }
37658b88779SPeter Maydell 
377244194feSPeter Maydell     if (get_cte(s, ite.icid, &cte) != MEMTX_OK) {
378be0ed8fbSPeter Maydell         return CMD_STALL;
379be0ed8fbSPeter Maydell     }
380d37cf49bSPeter Maydell     if (!cte.valid) {
381be0ed8fbSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
382d37cf49bSPeter Maydell                       "%s: invalid command attributes: invalid CTE\n",
383d37cf49bSPeter Maydell                       __func__);
384be0ed8fbSPeter Maydell         return CMD_CONTINUE;
385be0ed8fbSPeter Maydell     }
386be0ed8fbSPeter Maydell 
387c694cb4cSShashi Mallela     /*
388c694cb4cSShashi Mallela      * Current implementation only supports rdbase == procnum
389c694cb4cSShashi Mallela      * Hence rdbase physical address is ignored
390c694cb4cSShashi Mallela      */
391d37cf49bSPeter Maydell     if (cte.rdbase >= s->gicv3->num_cpu) {
392593a7cc2SPeter Maydell         return CMD_CONTINUE;
39317fb5e36SShashi Mallela     }
39417fb5e36SShashi Mallela 
39517fb5e36SShashi Mallela     if ((cmd == CLEAR) || (cmd == DISCARD)) {
396244194feSPeter Maydell         gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 0);
39717fb5e36SShashi Mallela     } else {
398244194feSPeter Maydell         gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 1);
39917fb5e36SShashi Mallela     }
40017fb5e36SShashi Mallela 
401c694cb4cSShashi Mallela     if (cmd == DISCARD) {
4027eb54267SPeter Maydell         ITEntry ite = {};
403c694cb4cSShashi Mallela         /* remove mapping from interrupt translation table */
4047eb54267SPeter Maydell         ite.valid = false;
405*93f4fdcdSPeter Maydell         return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
406c694cb4cSShashi Mallela     }
407*93f4fdcdSPeter Maydell     return CMD_CONTINUE_OK;
408c694cb4cSShashi Mallela }
4092a199036SPeter Maydell 
410b6f96009SPeter Maydell static ItsCmdResult process_its_cmd(GICv3ITSState *s, const uint64_t *cmdpkt,
411b6f96009SPeter Maydell                                     ItsCmdType cmd)
412c694cb4cSShashi Mallela {
413b6f96009SPeter Maydell     uint32_t devid, eventid;
414b6f96009SPeter Maydell 
415b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
416b6f96009SPeter Maydell     eventid = cmdpkt[1] & EVENTID_MASK;
417e4050980SPeter Maydell     switch (cmd) {
418e4050980SPeter Maydell     case INTERRUPT:
419e4050980SPeter Maydell         trace_gicv3_its_cmd_int(devid, eventid);
420e4050980SPeter Maydell         break;
421e4050980SPeter Maydell     case CLEAR:
422e4050980SPeter Maydell         trace_gicv3_its_cmd_clear(devid, eventid);
423e4050980SPeter Maydell         break;
424e4050980SPeter Maydell     case DISCARD:
425e4050980SPeter Maydell         trace_gicv3_its_cmd_discard(devid, eventid);
426e4050980SPeter Maydell         break;
427e4050980SPeter Maydell     default:
428e4050980SPeter Maydell         g_assert_not_reached();
429e4050980SPeter Maydell     }
430b6f96009SPeter Maydell     return do_process_its_cmd(s, devid, eventid, cmd);
431b6f96009SPeter Maydell }
432b6f96009SPeter Maydell 
433b6f96009SPeter Maydell static ItsCmdResult process_mapti(GICv3ITSState *s, const uint64_t *cmdpkt,
434b6f96009SPeter Maydell                                   bool ignore_pInt)
435b6f96009SPeter Maydell {
436c694cb4cSShashi Mallela     uint32_t devid, eventid;
437c694cb4cSShashi Mallela     uint32_t pIntid = 0;
4388f809f69SPeter Maydell     uint64_t num_eventids;
439c694cb4cSShashi Mallela     uint16_t icid = 0;
4404acf93e1SPeter Maydell     DTEntry dte;
4417eb54267SPeter Maydell     ITEntry ite;
442c694cb4cSShashi Mallela 
443b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
444b6f96009SPeter Maydell     eventid = cmdpkt[1] & EVENTID_MASK;
445e4050980SPeter Maydell     icid = cmdpkt[2] & ICID_MASK;
446c694cb4cSShashi Mallela 
447b87fab1cSPeter Maydell     if (ignore_pInt) {
448b87fab1cSPeter Maydell         pIntid = eventid;
449e4050980SPeter Maydell         trace_gicv3_its_cmd_mapi(devid, eventid, icid);
450b87fab1cSPeter Maydell     } else {
451b6f96009SPeter Maydell         pIntid = (cmdpkt[1] & pINTID_MASK) >> pINTID_SHIFT;
452e4050980SPeter Maydell         trace_gicv3_its_cmd_mapti(devid, eventid, icid, pIntid);
453c694cb4cSShashi Mallela     }
454c694cb4cSShashi Mallela 
4558b8bb014SPeter Maydell     if (devid >= s->dt.num_entries) {
456b13148d9SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
457b13148d9SPeter Maydell                       "%s: invalid command attributes: devid %d>=%d",
4588b8bb014SPeter Maydell                       __func__, devid, s->dt.num_entries);
459b13148d9SPeter Maydell         return CMD_CONTINUE;
460b13148d9SPeter Maydell     }
461b13148d9SPeter Maydell 
4624acf93e1SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
4630241f731SPeter Maydell         return CMD_STALL;
464c694cb4cSShashi Mallela     }
4654acf93e1SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
466c694cb4cSShashi Mallela 
467d7d359c4SPeter Maydell     if (icid >= s->ct.num_entries) {
468c694cb4cSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
469d7d359c4SPeter Maydell                       "%s: invalid ICID 0x%x >= 0x%x\n",
470d7d359c4SPeter Maydell                       __func__, icid, s->ct.num_entries);
471d7d359c4SPeter Maydell         return CMD_CONTINUE;
472d7d359c4SPeter Maydell     }
473d7d359c4SPeter Maydell 
474d7d359c4SPeter Maydell     if (!dte.valid) {
475d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
476d7d359c4SPeter Maydell                       "%s: no valid DTE for devid 0x%x\n", __func__, devid);
477d7d359c4SPeter Maydell         return CMD_CONTINUE;
478d7d359c4SPeter Maydell     }
479d7d359c4SPeter Maydell 
480d7d359c4SPeter Maydell     if (eventid >= num_eventids) {
481d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
482d7d359c4SPeter Maydell                       "%s: invalid event ID 0x%x >= 0x%" PRIx64 "\n",
483d7d359c4SPeter Maydell                       __func__, eventid, num_eventids);
484d7d359c4SPeter Maydell         return CMD_CONTINUE;
485d7d359c4SPeter Maydell     }
486d7d359c4SPeter Maydell 
487c3c9a090SPeter Maydell     if (!intid_in_lpi_range(pIntid)) {
488d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
489d7d359c4SPeter Maydell                       "%s: invalid interrupt ID 0x%x\n", __func__, pIntid);
4900241f731SPeter Maydell         return CMD_CONTINUE;
4910241f731SPeter Maydell     }
4920241f731SPeter Maydell 
493c694cb4cSShashi Mallela     /* add ite entry to interrupt translation table */
4947eb54267SPeter Maydell     ite.valid = true;
4957eb54267SPeter Maydell     ite.inttype = ITE_INTTYPE_PHYSICAL;
4967eb54267SPeter Maydell     ite.intid = pIntid;
4977eb54267SPeter Maydell     ite.icid = icid;
4987eb54267SPeter Maydell     ite.doorbell = INTID_SPURIOUS;
4997eb54267SPeter Maydell     ite.vpeid = 0;
500*93f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
501c694cb4cSShashi Mallela }
502c694cb4cSShashi Mallela 
5039de53de6SPeter Maydell static ItsCmdResult process_vmapti(GICv3ITSState *s, const uint64_t *cmdpkt,
5049de53de6SPeter Maydell                                    bool ignore_vintid)
5059de53de6SPeter Maydell {
5069de53de6SPeter Maydell     uint32_t devid, eventid, vintid, doorbell, vpeid;
5079de53de6SPeter Maydell     uint32_t num_eventids;
5089de53de6SPeter Maydell     DTEntry dte;
5099de53de6SPeter Maydell     ITEntry ite;
5109de53de6SPeter Maydell 
5119de53de6SPeter Maydell     if (!its_feature_virtual(s)) {
5129de53de6SPeter Maydell         return CMD_CONTINUE;
5139de53de6SPeter Maydell     }
5149de53de6SPeter Maydell 
5159de53de6SPeter Maydell     devid = FIELD_EX64(cmdpkt[0], VMAPTI_0, DEVICEID);
5169de53de6SPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], VMAPTI_1, EVENTID);
5179de53de6SPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VMAPTI_1, VPEID);
5189de53de6SPeter Maydell     doorbell = FIELD_EX64(cmdpkt[2], VMAPTI_2, DOORBELL);
5199de53de6SPeter Maydell     if (ignore_vintid) {
5209de53de6SPeter Maydell         vintid = eventid;
5219de53de6SPeter Maydell         trace_gicv3_its_cmd_vmapi(devid, eventid, vpeid, doorbell);
5229de53de6SPeter Maydell     } else {
5239de53de6SPeter Maydell         vintid = FIELD_EX64(cmdpkt[2], VMAPTI_2, VINTID);
5249de53de6SPeter Maydell         trace_gicv3_its_cmd_vmapti(devid, eventid, vpeid, vintid, doorbell);
5259de53de6SPeter Maydell     }
5269de53de6SPeter Maydell 
5279de53de6SPeter Maydell     if (devid >= s->dt.num_entries) {
5289de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5299de53de6SPeter Maydell                       "%s: invalid DeviceID 0x%x (must be less than 0x%x)\n",
5309de53de6SPeter Maydell                       __func__, devid, s->dt.num_entries);
5319de53de6SPeter Maydell         return CMD_CONTINUE;
5329de53de6SPeter Maydell     }
5339de53de6SPeter Maydell 
5349de53de6SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
5359de53de6SPeter Maydell         return CMD_STALL;
5369de53de6SPeter Maydell     }
5379de53de6SPeter Maydell 
5389de53de6SPeter Maydell     if (!dte.valid) {
5399de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5409de53de6SPeter Maydell                       "%s: no entry in device table for DeviceID 0x%x\n",
5419de53de6SPeter Maydell                       __func__, devid);
5429de53de6SPeter Maydell         return CMD_CONTINUE;
5439de53de6SPeter Maydell     }
5449de53de6SPeter Maydell 
5459de53de6SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
5469de53de6SPeter Maydell 
5479de53de6SPeter Maydell     if (eventid >= num_eventids) {
5489de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5499de53de6SPeter Maydell                       "%s: EventID 0x%x too large for DeviceID 0x%x "
5509de53de6SPeter Maydell                       "(must be less than 0x%x)\n",
5519de53de6SPeter Maydell                       __func__, eventid, devid, num_eventids);
5529de53de6SPeter Maydell         return CMD_CONTINUE;
5539de53de6SPeter Maydell     }
5549de53de6SPeter Maydell     if (!intid_in_lpi_range(vintid)) {
5559de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5569de53de6SPeter Maydell                       "%s: VIntID 0x%x not a valid LPI\n",
5579de53de6SPeter Maydell                       __func__, vintid);
5589de53de6SPeter Maydell         return CMD_CONTINUE;
5599de53de6SPeter Maydell     }
5609de53de6SPeter Maydell     if (!valid_doorbell(doorbell)) {
5619de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5629de53de6SPeter Maydell                       "%s: Doorbell %d not 1023 and not a valid LPI\n",
5639de53de6SPeter Maydell                       __func__, doorbell);
5649de53de6SPeter Maydell         return CMD_CONTINUE;
5659de53de6SPeter Maydell     }
5669de53de6SPeter Maydell     if (vpeid >= s->vpet.num_entries) {
5679de53de6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
5689de53de6SPeter Maydell                       "%s: VPEID 0x%x out of range (must be less than 0x%x)\n",
5699de53de6SPeter Maydell                       __func__, vpeid, s->vpet.num_entries);
5709de53de6SPeter Maydell         return CMD_CONTINUE;
5719de53de6SPeter Maydell     }
5729de53de6SPeter Maydell     /* add ite entry to interrupt translation table */
5739de53de6SPeter Maydell     ite.valid = true;
5749de53de6SPeter Maydell     ite.inttype = ITE_INTTYPE_VIRTUAL;
5759de53de6SPeter Maydell     ite.intid = vintid;
5769de53de6SPeter Maydell     ite.icid = 0;
5779de53de6SPeter Maydell     ite.doorbell = doorbell;
5789de53de6SPeter Maydell     ite.vpeid = vpeid;
579*93f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &ite) ? CMD_CONTINUE_OK : CMD_STALL;
5809de53de6SPeter Maydell }
5819de53de6SPeter Maydell 
58206985cc3SPeter Maydell /*
58306985cc3SPeter Maydell  * Update the Collection Table entry for @icid to @cte. Returns true
58406985cc3SPeter Maydell  * on success, false if there was a memory access error.
58506985cc3SPeter Maydell  */
58606985cc3SPeter Maydell static bool update_cte(GICv3ITSState *s, uint16_t icid, const CTEntry *cte)
5877eca39e0SShashi Mallela {
5887eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
589d050f80fSPeter Maydell     uint64_t entry_addr;
59006985cc3SPeter Maydell     uint64_t cteval = 0;
5917eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
5927eca39e0SShashi Mallela 
593930f40e9SPeter Maydell     trace_gicv3_its_cte_write(icid, cte->valid, cte->rdbase);
594930f40e9SPeter Maydell 
59506985cc3SPeter Maydell     if (cte->valid) {
5967eca39e0SShashi Mallela         /* add mapping entry to collection table */
59706985cc3SPeter Maydell         cteval = FIELD_DP64(cteval, CTE, VALID, 1);
59806985cc3SPeter Maydell         cteval = FIELD_DP64(cteval, CTE, RDBASE, cte->rdbase);
5997eca39e0SShashi Mallela     }
6007eca39e0SShashi Mallela 
601d050f80fSPeter Maydell     entry_addr = table_entry_addr(s, &s->ct, icid, &res);
6027eca39e0SShashi Mallela     if (res != MEMTX_OK) {
603d050f80fSPeter Maydell         /* memory access error: stall */
6047eca39e0SShashi Mallela         return false;
6057eca39e0SShashi Mallela     }
606d050f80fSPeter Maydell     if (entry_addr == -1) {
607d050f80fSPeter Maydell         /* No L2 table for this index: discard write and continue */
6087eca39e0SShashi Mallela         return true;
6097eca39e0SShashi Mallela     }
610d050f80fSPeter Maydell 
61106985cc3SPeter Maydell     address_space_stq_le(as, entry_addr, cteval, MEMTXATTRS_UNSPECIFIED, &res);
612d050f80fSPeter Maydell     return res == MEMTX_OK;
6137eca39e0SShashi Mallela }
6147eca39e0SShashi Mallela 
615b6f96009SPeter Maydell static ItsCmdResult process_mapc(GICv3ITSState *s, const uint64_t *cmdpkt)
6167eca39e0SShashi Mallela {
6177eca39e0SShashi Mallela     uint16_t icid;
61806985cc3SPeter Maydell     CTEntry cte;
6197eca39e0SShashi Mallela 
620b6f96009SPeter Maydell     icid = cmdpkt[2] & ICID_MASK;
62184d43d2eSPeter Maydell     cte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
62284d43d2eSPeter Maydell     if (cte.valid) {
62306985cc3SPeter Maydell         cte.rdbase = (cmdpkt[2] & R_MAPC_RDBASE_MASK) >> R_MAPC_RDBASE_SHIFT;
62406985cc3SPeter Maydell         cte.rdbase &= RDBASE_PROCNUM_MASK;
62584d43d2eSPeter Maydell     } else {
62684d43d2eSPeter Maydell         cte.rdbase = 0;
62784d43d2eSPeter Maydell     }
628e4050980SPeter Maydell     trace_gicv3_its_cmd_mapc(icid, cte.rdbase, cte.valid);
6297eca39e0SShashi Mallela 
63084d43d2eSPeter Maydell     if (icid >= s->ct.num_entries) {
631c7ca3ad5SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR, "ITS MAPC: invalid ICID 0x%x\n", icid);
63284d43d2eSPeter Maydell         return CMD_CONTINUE;
63384d43d2eSPeter Maydell     }
63484d43d2eSPeter Maydell     if (cte.valid && cte.rdbase >= s->gicv3->num_cpu) {
6357eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
636c7ca3ad5SPeter Maydell                       "ITS MAPC: invalid RDBASE %u\n", cte.rdbase);
637f6675196SPeter Maydell         return CMD_CONTINUE;
6387eca39e0SShashi Mallela     }
6397eca39e0SShashi Mallela 
640*93f4fdcdSPeter Maydell     return update_cte(s, icid, &cte) ? CMD_CONTINUE_OK : CMD_STALL;
6417eca39e0SShashi Mallela }
6427eca39e0SShashi Mallela 
64322d62b08SPeter Maydell /*
64422d62b08SPeter Maydell  * Update the Device Table entry for @devid to @dte. Returns true
64522d62b08SPeter Maydell  * on success, false if there was a memory access error.
64622d62b08SPeter Maydell  */
64722d62b08SPeter Maydell static bool update_dte(GICv3ITSState *s, uint32_t devid, const DTEntry *dte)
6487eca39e0SShashi Mallela {
6497eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
650d050f80fSPeter Maydell     uint64_t entry_addr;
65122d62b08SPeter Maydell     uint64_t dteval = 0;
6527eca39e0SShashi Mallela     MemTxResult res = MEMTX_OK;
6537eca39e0SShashi Mallela 
654930f40e9SPeter Maydell     trace_gicv3_its_dte_write(devid, dte->valid, dte->size, dte->ittaddr);
655930f40e9SPeter Maydell 
65622d62b08SPeter Maydell     if (dte->valid) {
6577eca39e0SShashi Mallela         /* add mapping entry to device table */
65822d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, VALID, 1);
65922d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, SIZE, dte->size);
66022d62b08SPeter Maydell         dteval = FIELD_DP64(dteval, DTE, ITTADDR, dte->ittaddr);
6617eca39e0SShashi Mallela     }
6627eca39e0SShashi Mallela 
663d050f80fSPeter Maydell     entry_addr = table_entry_addr(s, &s->dt, devid, &res);
6647eca39e0SShashi Mallela     if (res != MEMTX_OK) {
665d050f80fSPeter Maydell         /* memory access error: stall */
6667eca39e0SShashi Mallela         return false;
6677eca39e0SShashi Mallela     }
668d050f80fSPeter Maydell     if (entry_addr == -1) {
669d050f80fSPeter Maydell         /* No L2 table for this index: discard write and continue */
6707eca39e0SShashi Mallela         return true;
6717eca39e0SShashi Mallela     }
67222d62b08SPeter Maydell     address_space_stq_le(as, entry_addr, dteval, MEMTXATTRS_UNSPECIFIED, &res);
673d050f80fSPeter Maydell     return res == MEMTX_OK;
6747eca39e0SShashi Mallela }
6757eca39e0SShashi Mallela 
676b6f96009SPeter Maydell static ItsCmdResult process_mapd(GICv3ITSState *s, const uint64_t *cmdpkt)
6777eca39e0SShashi Mallela {
6787eca39e0SShashi Mallela     uint32_t devid;
67922d62b08SPeter Maydell     DTEntry dte;
6807eca39e0SShashi Mallela 
681b6f96009SPeter Maydell     devid = (cmdpkt[0] & DEVID_MASK) >> DEVID_SHIFT;
68222d62b08SPeter Maydell     dte.size = cmdpkt[1] & SIZE_MASK;
68322d62b08SPeter Maydell     dte.ittaddr = (cmdpkt[2] & ITTADDR_MASK) >> ITTADDR_SHIFT;
68422d62b08SPeter Maydell     dte.valid = cmdpkt[2] & CMD_FIELD_VALID_MASK;
6857eca39e0SShashi Mallela 
686e4050980SPeter Maydell     trace_gicv3_its_cmd_mapd(devid, dte.size, dte.ittaddr, dte.valid);
687e4050980SPeter Maydell 
688d7d359c4SPeter Maydell     if (devid >= s->dt.num_entries) {
6897eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
690d7d359c4SPeter Maydell                       "ITS MAPD: invalid device ID field 0x%x >= 0x%x\n",
691d7d359c4SPeter Maydell                       devid, s->dt.num_entries);
692d7d359c4SPeter Maydell         return CMD_CONTINUE;
693d7d359c4SPeter Maydell     }
694d7d359c4SPeter Maydell 
695d7d359c4SPeter Maydell     if (dte.size > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
696d7d359c4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
697d7d359c4SPeter Maydell                       "ITS MAPD: invalid size %d\n", dte.size);
69800d46e72SPeter Maydell         return CMD_CONTINUE;
6997eca39e0SShashi Mallela     }
7007eca39e0SShashi Mallela 
701*93f4fdcdSPeter Maydell     return update_dte(s, devid, &dte) ? CMD_CONTINUE_OK : CMD_STALL;
7027eca39e0SShashi Mallela }
7037eca39e0SShashi Mallela 
704b6f96009SPeter Maydell static ItsCmdResult process_movall(GICv3ITSState *s, const uint64_t *cmdpkt)
705f6d1d9b4SPeter Maydell {
706f6d1d9b4SPeter Maydell     uint64_t rd1, rd2;
707f6d1d9b4SPeter Maydell 
708b6f96009SPeter Maydell     rd1 = FIELD_EX64(cmdpkt[2], MOVALL_2, RDBASE1);
709b6f96009SPeter Maydell     rd2 = FIELD_EX64(cmdpkt[3], MOVALL_3, RDBASE2);
710f6d1d9b4SPeter Maydell 
711e4050980SPeter Maydell     trace_gicv3_its_cmd_movall(rd1, rd2);
712e4050980SPeter Maydell 
713f6d1d9b4SPeter Maydell     if (rd1 >= s->gicv3->num_cpu) {
714f6d1d9b4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
715f6d1d9b4SPeter Maydell                       "%s: RDBASE1 %" PRId64
716f6d1d9b4SPeter Maydell                       " out of range (must be less than %d)\n",
717f6d1d9b4SPeter Maydell                       __func__, rd1, s->gicv3->num_cpu);
718f6d1d9b4SPeter Maydell         return CMD_CONTINUE;
719f6d1d9b4SPeter Maydell     }
720f6d1d9b4SPeter Maydell     if (rd2 >= s->gicv3->num_cpu) {
721f6d1d9b4SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
722f6d1d9b4SPeter Maydell                       "%s: RDBASE2 %" PRId64
723f6d1d9b4SPeter Maydell                       " out of range (must be less than %d)\n",
724f6d1d9b4SPeter Maydell                       __func__, rd2, s->gicv3->num_cpu);
725f6d1d9b4SPeter Maydell         return CMD_CONTINUE;
726f6d1d9b4SPeter Maydell     }
727f6d1d9b4SPeter Maydell 
728f6d1d9b4SPeter Maydell     if (rd1 == rd2) {
729f6d1d9b4SPeter Maydell         /* Move to same target must succeed as a no-op */
730*93f4fdcdSPeter Maydell         return CMD_CONTINUE_OK;
731f6d1d9b4SPeter Maydell     }
732f6d1d9b4SPeter Maydell 
733f6d1d9b4SPeter Maydell     /* Move all pending LPIs from redistributor 1 to redistributor 2 */
734f6d1d9b4SPeter Maydell     gicv3_redist_movall_lpis(&s->gicv3->cpu[rd1], &s->gicv3->cpu[rd2]);
735f6d1d9b4SPeter Maydell 
736*93f4fdcdSPeter Maydell     return CMD_CONTINUE_OK;
737f6d1d9b4SPeter Maydell }
738f6d1d9b4SPeter Maydell 
739b6f96009SPeter Maydell static ItsCmdResult process_movi(GICv3ITSState *s, const uint64_t *cmdpkt)
740961b4912SPeter Maydell {
741244194feSPeter Maydell     uint32_t devid, eventid;
742244194feSPeter Maydell     uint16_t new_icid;
743961b4912SPeter Maydell     uint64_t num_eventids;
7444acf93e1SPeter Maydell     DTEntry dte;
745d37cf49bSPeter Maydell     CTEntry old_cte, new_cte;
746244194feSPeter Maydell     ITEntry old_ite;
747961b4912SPeter Maydell 
748b6f96009SPeter Maydell     devid = FIELD_EX64(cmdpkt[0], MOVI_0, DEVICEID);
749b6f96009SPeter Maydell     eventid = FIELD_EX64(cmdpkt[1], MOVI_1, EVENTID);
750b6f96009SPeter Maydell     new_icid = FIELD_EX64(cmdpkt[2], MOVI_2, ICID);
751961b4912SPeter Maydell 
752e4050980SPeter Maydell     trace_gicv3_its_cmd_movi(devid, eventid, new_icid);
753e4050980SPeter Maydell 
754961b4912SPeter Maydell     if (devid >= s->dt.num_entries) {
755961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
756961b4912SPeter Maydell                       "%s: invalid command attributes: devid %d>=%d",
757961b4912SPeter Maydell                       __func__, devid, s->dt.num_entries);
758961b4912SPeter Maydell         return CMD_CONTINUE;
759961b4912SPeter Maydell     }
7604acf93e1SPeter Maydell     if (get_dte(s, devid, &dte) != MEMTX_OK) {
761961b4912SPeter Maydell         return CMD_STALL;
762961b4912SPeter Maydell     }
763961b4912SPeter Maydell 
7644acf93e1SPeter Maydell     if (!dte.valid) {
765961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
766961b4912SPeter Maydell                       "%s: invalid command attributes: "
7674acf93e1SPeter Maydell                       "invalid dte for %d\n", __func__, devid);
768961b4912SPeter Maydell         return CMD_CONTINUE;
769961b4912SPeter Maydell     }
770961b4912SPeter Maydell 
7714acf93e1SPeter Maydell     num_eventids = 1ULL << (dte.size + 1);
772961b4912SPeter Maydell     if (eventid >= num_eventids) {
773961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
774961b4912SPeter Maydell                       "%s: invalid command attributes: eventid %d >= %"
775961b4912SPeter Maydell                       PRId64 "\n",
776961b4912SPeter Maydell                       __func__, eventid, num_eventids);
777961b4912SPeter Maydell         return CMD_CONTINUE;
778961b4912SPeter Maydell     }
779961b4912SPeter Maydell 
780244194feSPeter Maydell     if (get_ite(s, eventid, &dte, &old_ite) != MEMTX_OK) {
781961b4912SPeter Maydell         return CMD_STALL;
782961b4912SPeter Maydell     }
783961b4912SPeter Maydell 
784244194feSPeter Maydell     if (!old_ite.valid || old_ite.inttype != ITE_INTTYPE_PHYSICAL) {
785961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
786961b4912SPeter Maydell                       "%s: invalid command attributes: invalid ITE\n",
787961b4912SPeter Maydell                       __func__);
788961b4912SPeter Maydell         return CMD_CONTINUE;
789961b4912SPeter Maydell     }
790961b4912SPeter Maydell 
791244194feSPeter Maydell     if (old_ite.icid >= s->ct.num_entries) {
792961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
793961b4912SPeter Maydell                       "%s: invalid ICID 0x%x in ITE (table corrupted?)\n",
794244194feSPeter Maydell                       __func__, old_ite.icid);
795961b4912SPeter Maydell         return CMD_CONTINUE;
796961b4912SPeter Maydell     }
797961b4912SPeter Maydell 
798961b4912SPeter Maydell     if (new_icid >= s->ct.num_entries) {
799961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
800961b4912SPeter Maydell                       "%s: invalid command attributes: ICID 0x%x\n",
801961b4912SPeter Maydell                       __func__, new_icid);
802961b4912SPeter Maydell         return CMD_CONTINUE;
803961b4912SPeter Maydell     }
804961b4912SPeter Maydell 
805244194feSPeter Maydell     if (get_cte(s, old_ite.icid, &old_cte) != MEMTX_OK) {
806961b4912SPeter Maydell         return CMD_STALL;
807961b4912SPeter Maydell     }
808d37cf49bSPeter Maydell     if (!old_cte.valid) {
809961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
810961b4912SPeter Maydell                       "%s: invalid command attributes: "
811d37cf49bSPeter Maydell                       "invalid CTE for old ICID 0x%x\n",
812244194feSPeter Maydell                       __func__, old_ite.icid);
813961b4912SPeter Maydell         return CMD_CONTINUE;
814961b4912SPeter Maydell     }
815961b4912SPeter Maydell 
816d37cf49bSPeter Maydell     if (get_cte(s, new_icid, &new_cte) != MEMTX_OK) {
817961b4912SPeter Maydell         return CMD_STALL;
818961b4912SPeter Maydell     }
819d37cf49bSPeter Maydell     if (!new_cte.valid) {
820961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
821961b4912SPeter Maydell                       "%s: invalid command attributes: "
822d37cf49bSPeter Maydell                       "invalid CTE for new ICID 0x%x\n",
823d37cf49bSPeter Maydell                       __func__, new_icid);
824961b4912SPeter Maydell         return CMD_CONTINUE;
825961b4912SPeter Maydell     }
826961b4912SPeter Maydell 
827d37cf49bSPeter Maydell     if (old_cte.rdbase >= s->gicv3->num_cpu) {
828961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
829d37cf49bSPeter Maydell                       "%s: CTE has invalid rdbase 0x%x\n",
830d37cf49bSPeter Maydell                       __func__, old_cte.rdbase);
831961b4912SPeter Maydell         return CMD_CONTINUE;
832961b4912SPeter Maydell     }
833961b4912SPeter Maydell 
834d37cf49bSPeter Maydell     if (new_cte.rdbase >= s->gicv3->num_cpu) {
835961b4912SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
836d37cf49bSPeter Maydell                       "%s: CTE has invalid rdbase 0x%x\n",
837d37cf49bSPeter Maydell                       __func__, new_cte.rdbase);
838961b4912SPeter Maydell         return CMD_CONTINUE;
839961b4912SPeter Maydell     }
840961b4912SPeter Maydell 
841d37cf49bSPeter Maydell     if (old_cte.rdbase != new_cte.rdbase) {
842961b4912SPeter Maydell         /* Move the LPI from the old redistributor to the new one */
843d37cf49bSPeter Maydell         gicv3_redist_mov_lpi(&s->gicv3->cpu[old_cte.rdbase],
844d37cf49bSPeter Maydell                              &s->gicv3->cpu[new_cte.rdbase],
845244194feSPeter Maydell                              old_ite.intid);
846961b4912SPeter Maydell     }
847961b4912SPeter Maydell 
848961b4912SPeter Maydell     /* Update the ICID field in the interrupt translation table entry */
8497eb54267SPeter Maydell     old_ite.icid = new_icid;
850*93f4fdcdSPeter Maydell     return update_ite(s, eventid, &dte, &old_ite) ? CMD_CONTINUE_OK : CMD_STALL;
851961b4912SPeter Maydell }
852961b4912SPeter Maydell 
8537eca39e0SShashi Mallela /*
8540cdf7a5dSPeter Maydell  * Update the vPE Table entry at index @vpeid with the entry @vte.
8550cdf7a5dSPeter Maydell  * Returns true on success, false if there was a memory access error.
8560cdf7a5dSPeter Maydell  */
8570cdf7a5dSPeter Maydell static bool update_vte(GICv3ITSState *s, uint32_t vpeid, const VTEntry *vte)
8580cdf7a5dSPeter Maydell {
8590cdf7a5dSPeter Maydell     AddressSpace *as = &s->gicv3->dma_as;
8600cdf7a5dSPeter Maydell     uint64_t entry_addr;
8610cdf7a5dSPeter Maydell     uint64_t vteval = 0;
8620cdf7a5dSPeter Maydell     MemTxResult res = MEMTX_OK;
8630cdf7a5dSPeter Maydell 
8640cdf7a5dSPeter Maydell     trace_gicv3_its_vte_write(vpeid, vte->valid, vte->vptsize, vte->vptaddr,
8650cdf7a5dSPeter Maydell                               vte->rdbase);
8660cdf7a5dSPeter Maydell 
8670cdf7a5dSPeter Maydell     if (vte->valid) {
8680cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VALID, 1);
8690cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VPTSIZE, vte->vptsize);
8700cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, VPTADDR, vte->vptaddr);
8710cdf7a5dSPeter Maydell         vteval = FIELD_DP64(vteval, VTE, RDBASE, vte->rdbase);
8720cdf7a5dSPeter Maydell     }
8730cdf7a5dSPeter Maydell 
8740cdf7a5dSPeter Maydell     entry_addr = table_entry_addr(s, &s->vpet, vpeid, &res);
8750cdf7a5dSPeter Maydell     if (res != MEMTX_OK) {
8760cdf7a5dSPeter Maydell         return false;
8770cdf7a5dSPeter Maydell     }
8780cdf7a5dSPeter Maydell     if (entry_addr == -1) {
8790cdf7a5dSPeter Maydell         /* No L2 table for this index: discard write and continue */
8800cdf7a5dSPeter Maydell         return true;
8810cdf7a5dSPeter Maydell     }
8820cdf7a5dSPeter Maydell     address_space_stq_le(as, entry_addr, vteval, MEMTXATTRS_UNSPECIFIED, &res);
8830cdf7a5dSPeter Maydell     return res == MEMTX_OK;
8840cdf7a5dSPeter Maydell }
8850cdf7a5dSPeter Maydell 
8860cdf7a5dSPeter Maydell static ItsCmdResult process_vmapp(GICv3ITSState *s, const uint64_t *cmdpkt)
8870cdf7a5dSPeter Maydell {
8880cdf7a5dSPeter Maydell     VTEntry vte;
8890cdf7a5dSPeter Maydell     uint32_t vpeid;
8900cdf7a5dSPeter Maydell 
8910cdf7a5dSPeter Maydell     if (!its_feature_virtual(s)) {
8920cdf7a5dSPeter Maydell         return CMD_CONTINUE;
8930cdf7a5dSPeter Maydell     }
8940cdf7a5dSPeter Maydell 
8950cdf7a5dSPeter Maydell     vpeid = FIELD_EX64(cmdpkt[1], VMAPP_1, VPEID);
8960cdf7a5dSPeter Maydell     vte.rdbase = FIELD_EX64(cmdpkt[2], VMAPP_2, RDBASE);
8970cdf7a5dSPeter Maydell     vte.valid = FIELD_EX64(cmdpkt[2], VMAPP_2, V);
8980cdf7a5dSPeter Maydell     vte.vptsize = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTSIZE);
8990cdf7a5dSPeter Maydell     vte.vptaddr = FIELD_EX64(cmdpkt[3], VMAPP_3, VPTADDR);
9000cdf7a5dSPeter Maydell 
9010cdf7a5dSPeter Maydell     trace_gicv3_its_cmd_vmapp(vpeid, vte.rdbase, vte.valid,
9020cdf7a5dSPeter Maydell                               vte.vptaddr, vte.vptsize);
9030cdf7a5dSPeter Maydell 
9040cdf7a5dSPeter Maydell     /*
9050cdf7a5dSPeter Maydell      * For GICv4.0 the VPT_size field is only 5 bits, whereas we
9060cdf7a5dSPeter Maydell      * define our field macros to include the full GICv4.1 8 bits.
9070cdf7a5dSPeter Maydell      * The range check on VPT_size will catch the cases where
9080cdf7a5dSPeter Maydell      * the guest set the RES0-in-GICv4.0 bits [7:6].
9090cdf7a5dSPeter Maydell      */
9100cdf7a5dSPeter Maydell     if (vte.vptsize > FIELD_EX64(s->typer, GITS_TYPER, IDBITS)) {
9110cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
9120cdf7a5dSPeter Maydell                       "%s: invalid VPT_size 0x%x\n", __func__, vte.vptsize);
9130cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9140cdf7a5dSPeter Maydell     }
9150cdf7a5dSPeter Maydell 
9160cdf7a5dSPeter Maydell     if (vte.valid && vte.rdbase >= s->gicv3->num_cpu) {
9170cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
9180cdf7a5dSPeter Maydell                       "%s: invalid rdbase 0x%x\n", __func__, vte.rdbase);
9190cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9200cdf7a5dSPeter Maydell     }
9210cdf7a5dSPeter Maydell 
9220cdf7a5dSPeter Maydell     if (vpeid >= s->vpet.num_entries) {
9230cdf7a5dSPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
9240cdf7a5dSPeter Maydell                       "%s: VPEID 0x%x out of range (must be less than 0x%x)\n",
9250cdf7a5dSPeter Maydell                       __func__, vpeid, s->vpet.num_entries);
9260cdf7a5dSPeter Maydell         return CMD_CONTINUE;
9270cdf7a5dSPeter Maydell     }
9280cdf7a5dSPeter Maydell 
929*93f4fdcdSPeter Maydell     return update_vte(s, vpeid, &vte) ? CMD_CONTINUE_OK : CMD_STALL;
9300cdf7a5dSPeter Maydell }
9310cdf7a5dSPeter Maydell 
9320cdf7a5dSPeter Maydell /*
9337eca39e0SShashi Mallela  * Current implementation blocks until all
9347eca39e0SShashi Mallela  * commands are processed
9357eca39e0SShashi Mallela  */
9367eca39e0SShashi Mallela static void process_cmdq(GICv3ITSState *s)
9377eca39e0SShashi Mallela {
9387eca39e0SShashi Mallela     uint32_t wr_offset = 0;
9397eca39e0SShashi Mallela     uint32_t rd_offset = 0;
9407eca39e0SShashi Mallela     uint32_t cq_offset = 0;
9417eca39e0SShashi Mallela     AddressSpace *as = &s->gicv3->dma_as;
9427eca39e0SShashi Mallela     uint8_t cmd;
94317fb5e36SShashi Mallela     int i;
9447eca39e0SShashi Mallela 
9458d2d6dd9SPeter Maydell     if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
9467eca39e0SShashi Mallela         return;
9477eca39e0SShashi Mallela     }
9487eca39e0SShashi Mallela 
9497eca39e0SShashi Mallela     wr_offset = FIELD_EX64(s->cwriter, GITS_CWRITER, OFFSET);
9507eca39e0SShashi Mallela 
95180dcd37fSPeter Maydell     if (wr_offset >= s->cq.num_entries) {
9527eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
9537eca39e0SShashi Mallela                       "%s: invalid write offset "
9547eca39e0SShashi Mallela                       "%d\n", __func__, wr_offset);
9557eca39e0SShashi Mallela         return;
9567eca39e0SShashi Mallela     }
9577eca39e0SShashi Mallela 
9587eca39e0SShashi Mallela     rd_offset = FIELD_EX64(s->creadr, GITS_CREADR, OFFSET);
9597eca39e0SShashi Mallela 
96080dcd37fSPeter Maydell     if (rd_offset >= s->cq.num_entries) {
9617eca39e0SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
9627eca39e0SShashi Mallela                       "%s: invalid read offset "
9637eca39e0SShashi Mallela                       "%d\n", __func__, rd_offset);
9647eca39e0SShashi Mallela         return;
9657eca39e0SShashi Mallela     }
9667eca39e0SShashi Mallela 
9677eca39e0SShashi Mallela     while (wr_offset != rd_offset) {
968*93f4fdcdSPeter Maydell         ItsCmdResult result = CMD_CONTINUE_OK;
969b6f96009SPeter Maydell         void *hostmem;
970b6f96009SPeter Maydell         hwaddr buflen;
971b6f96009SPeter Maydell         uint64_t cmdpkt[GITS_CMDQ_ENTRY_WORDS];
972ef011555SPeter Maydell 
9737eca39e0SShashi Mallela         cq_offset = (rd_offset * GITS_CMDQ_ENTRY_SIZE);
974b6f96009SPeter Maydell 
975b6f96009SPeter Maydell         buflen = GITS_CMDQ_ENTRY_SIZE;
976b6f96009SPeter Maydell         hostmem = address_space_map(as, s->cq.base_addr + cq_offset,
977b6f96009SPeter Maydell                                     &buflen, false, MEMTXATTRS_UNSPECIFIED);
978b6f96009SPeter Maydell         if (!hostmem || buflen != GITS_CMDQ_ENTRY_SIZE) {
979b6f96009SPeter Maydell             if (hostmem) {
980b6f96009SPeter Maydell                 address_space_unmap(as, hostmem, buflen, false, 0);
981b6f96009SPeter Maydell             }
982f0b4b2a2SPeter Maydell             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
983f0b4b2a2SPeter Maydell             qemu_log_mask(LOG_GUEST_ERROR,
984f0b4b2a2SPeter Maydell                           "%s: could not read command at 0x%" PRIx64 "\n",
985f0b4b2a2SPeter Maydell                           __func__, s->cq.base_addr + cq_offset);
986f0b4b2a2SPeter Maydell             break;
9877eca39e0SShashi Mallela         }
988b6f96009SPeter Maydell         for (i = 0; i < ARRAY_SIZE(cmdpkt); i++) {
989b6f96009SPeter Maydell             cmdpkt[i] = ldq_le_p(hostmem + i * sizeof(uint64_t));
990b6f96009SPeter Maydell         }
991b6f96009SPeter Maydell         address_space_unmap(as, hostmem, buflen, false, 0);
992f0b4b2a2SPeter Maydell 
993b6f96009SPeter Maydell         cmd = cmdpkt[0] & CMD_MASK;
9947eca39e0SShashi Mallela 
995195209d3SPeter Maydell         trace_gicv3_its_process_command(rd_offset, cmd);
996195209d3SPeter Maydell 
9977eca39e0SShashi Mallela         switch (cmd) {
9987eca39e0SShashi Mallela         case GITS_CMD_INT:
999b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, INTERRUPT);
10007eca39e0SShashi Mallela             break;
10017eca39e0SShashi Mallela         case GITS_CMD_CLEAR:
1002b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, CLEAR);
10037eca39e0SShashi Mallela             break;
10047eca39e0SShashi Mallela         case GITS_CMD_SYNC:
10057eca39e0SShashi Mallela             /*
10067eca39e0SShashi Mallela              * Current implementation makes a blocking synchronous call
10077eca39e0SShashi Mallela              * for every command issued earlier, hence the internal state
10087eca39e0SShashi Mallela              * is already consistent by the time SYNC command is executed.
10097eca39e0SShashi Mallela              * Hence no further processing is required for SYNC command.
10107eca39e0SShashi Mallela              */
1011e4050980SPeter Maydell             trace_gicv3_its_cmd_sync();
10127eca39e0SShashi Mallela             break;
10137eca39e0SShashi Mallela         case GITS_CMD_MAPD:
1014b6f96009SPeter Maydell             result = process_mapd(s, cmdpkt);
10157eca39e0SShashi Mallela             break;
10167eca39e0SShashi Mallela         case GITS_CMD_MAPC:
1017b6f96009SPeter Maydell             result = process_mapc(s, cmdpkt);
10187eca39e0SShashi Mallela             break;
10197eca39e0SShashi Mallela         case GITS_CMD_MAPTI:
1020b6f96009SPeter Maydell             result = process_mapti(s, cmdpkt, false);
10217eca39e0SShashi Mallela             break;
10227eca39e0SShashi Mallela         case GITS_CMD_MAPI:
1023b6f96009SPeter Maydell             result = process_mapti(s, cmdpkt, true);
10247eca39e0SShashi Mallela             break;
10257eca39e0SShashi Mallela         case GITS_CMD_DISCARD:
1026b6f96009SPeter Maydell             result = process_its_cmd(s, cmdpkt, DISCARD);
10277eca39e0SShashi Mallela             break;
10287eca39e0SShashi Mallela         case GITS_CMD_INV:
10297eca39e0SShashi Mallela         case GITS_CMD_INVALL:
103017fb5e36SShashi Mallela             /*
103117fb5e36SShashi Mallela              * Current implementation doesn't cache any ITS tables,
103217fb5e36SShashi Mallela              * but the calculated lpi priority information. We only
103317fb5e36SShashi Mallela              * need to trigger lpi priority re-calculation to be in
103417fb5e36SShashi Mallela              * sync with LPI config table or pending table changes.
103517fb5e36SShashi Mallela              */
1036e4050980SPeter Maydell             trace_gicv3_its_cmd_inv();
103717fb5e36SShashi Mallela             for (i = 0; i < s->gicv3->num_cpu; i++) {
103817fb5e36SShashi Mallela                 gicv3_redist_update_lpi(&s->gicv3->cpu[i]);
103917fb5e36SShashi Mallela             }
10407eca39e0SShashi Mallela             break;
1041961b4912SPeter Maydell         case GITS_CMD_MOVI:
1042b6f96009SPeter Maydell             result = process_movi(s, cmdpkt);
1043961b4912SPeter Maydell             break;
1044f6d1d9b4SPeter Maydell         case GITS_CMD_MOVALL:
1045b6f96009SPeter Maydell             result = process_movall(s, cmdpkt);
1046f6d1d9b4SPeter Maydell             break;
10479de53de6SPeter Maydell         case GITS_CMD_VMAPTI:
10489de53de6SPeter Maydell             result = process_vmapti(s, cmdpkt, false);
10499de53de6SPeter Maydell             break;
10509de53de6SPeter Maydell         case GITS_CMD_VMAPI:
10519de53de6SPeter Maydell             result = process_vmapti(s, cmdpkt, true);
10529de53de6SPeter Maydell             break;
10530cdf7a5dSPeter Maydell         case GITS_CMD_VMAPP:
10540cdf7a5dSPeter Maydell             result = process_vmapp(s, cmdpkt);
10550cdf7a5dSPeter Maydell             break;
10567eca39e0SShashi Mallela         default:
1057e4050980SPeter Maydell             trace_gicv3_its_cmd_unknown(cmd);
10587eca39e0SShashi Mallela             break;
10597eca39e0SShashi Mallela         }
1060*93f4fdcdSPeter Maydell         if (result != CMD_STALL) {
1061*93f4fdcdSPeter Maydell             /* CMD_CONTINUE or CMD_CONTINUE_OK */
10627eca39e0SShashi Mallela             rd_offset++;
106380dcd37fSPeter Maydell             rd_offset %= s->cq.num_entries;
10647eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, OFFSET, rd_offset);
10657eca39e0SShashi Mallela         } else {
1066ef011555SPeter Maydell             /* CMD_STALL */
10677eca39e0SShashi Mallela             s->creadr = FIELD_DP64(s->creadr, GITS_CREADR, STALLED, 1);
10687eca39e0SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
1069ef011555SPeter Maydell                           "%s: 0x%x cmd processing failed, stalling\n",
1070ef011555SPeter Maydell                           __func__, cmd);
10717eca39e0SShashi Mallela             break;
10727eca39e0SShashi Mallela         }
10737eca39e0SShashi Mallela     }
10747eca39e0SShashi Mallela }
10757eca39e0SShashi Mallela 
10761b08e436SShashi Mallela /*
10771b08e436SShashi Mallela  * This function extracts the ITS Device and Collection table specific
10781b08e436SShashi Mallela  * parameters (like base_addr, size etc) from GITS_BASER register.
10791b08e436SShashi Mallela  * It is called during ITS enable and also during post_load migration
10801b08e436SShashi Mallela  */
10811b08e436SShashi Mallela static void extract_table_params(GICv3ITSState *s)
10821b08e436SShashi Mallela {
10831b08e436SShashi Mallela     uint16_t num_pages = 0;
10841b08e436SShashi Mallela     uint8_t  page_sz_type;
10851b08e436SShashi Mallela     uint8_t type;
10861b08e436SShashi Mallela     uint32_t page_sz = 0;
10871b08e436SShashi Mallela     uint64_t value;
10881b08e436SShashi Mallela 
10891b08e436SShashi Mallela     for (int i = 0; i < 8; i++) {
1090e5487a41SPeter Maydell         TableDesc *td;
1091e5487a41SPeter Maydell         int idbits;
1092e5487a41SPeter Maydell 
10931b08e436SShashi Mallela         value = s->baser[i];
10941b08e436SShashi Mallela 
10951b08e436SShashi Mallela         if (!value) {
10961b08e436SShashi Mallela             continue;
10971b08e436SShashi Mallela         }
10981b08e436SShashi Mallela 
10991b08e436SShashi Mallela         page_sz_type = FIELD_EX64(value, GITS_BASER, PAGESIZE);
11001b08e436SShashi Mallela 
11011b08e436SShashi Mallela         switch (page_sz_type) {
11021b08e436SShashi Mallela         case 0:
11031b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_4K;
11041b08e436SShashi Mallela             break;
11051b08e436SShashi Mallela 
11061b08e436SShashi Mallela         case 1:
11071b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_16K;
11081b08e436SShashi Mallela             break;
11091b08e436SShashi Mallela 
11101b08e436SShashi Mallela         case 2:
11111b08e436SShashi Mallela         case 3:
11121b08e436SShashi Mallela             page_sz = GITS_PAGE_SIZE_64K;
11131b08e436SShashi Mallela             break;
11141b08e436SShashi Mallela 
11151b08e436SShashi Mallela         default:
11161b08e436SShashi Mallela             g_assert_not_reached();
11171b08e436SShashi Mallela         }
11181b08e436SShashi Mallela 
11191b08e436SShashi Mallela         num_pages = FIELD_EX64(value, GITS_BASER, SIZE) + 1;
11201b08e436SShashi Mallela 
11211b08e436SShashi Mallela         type = FIELD_EX64(value, GITS_BASER, TYPE);
11221b08e436SShashi Mallela 
11231b08e436SShashi Mallela         switch (type) {
11241b08e436SShashi Mallela         case GITS_BASER_TYPE_DEVICE:
1125e5487a41SPeter Maydell             td = &s->dt;
1126e5487a41SPeter Maydell             idbits = FIELD_EX64(s->typer, GITS_TYPER, DEVBITS) + 1;
112762df780eSPeter Maydell             break;
11281b08e436SShashi Mallela         case GITS_BASER_TYPE_COLLECTION:
1129e5487a41SPeter Maydell             td = &s->ct;
11301b08e436SShashi Mallela             if (FIELD_EX64(s->typer, GITS_TYPER, CIL)) {
1131e5487a41SPeter Maydell                 idbits = FIELD_EX64(s->typer, GITS_TYPER, CIDBITS) + 1;
11321b08e436SShashi Mallela             } else {
11331b08e436SShashi Mallela                 /* 16-bit CollectionId supported when CIL == 0 */
1134e5487a41SPeter Maydell                 idbits = 16;
11351b08e436SShashi Mallela             }
11361b08e436SShashi Mallela             break;
113750d84584SPeter Maydell         case GITS_BASER_TYPE_VPE:
113850d84584SPeter Maydell             td = &s->vpet;
113950d84584SPeter Maydell             /*
114050d84584SPeter Maydell              * For QEMU vPEIDs are always 16 bits. (GICv4.1 allows an
114150d84584SPeter Maydell              * implementation to implement fewer bits and report this
114250d84584SPeter Maydell              * via GICD_TYPER2.)
114350d84584SPeter Maydell              */
114450d84584SPeter Maydell             idbits = 16;
114550d84584SPeter Maydell             break;
11461b08e436SShashi Mallela         default:
1147e5487a41SPeter Maydell             /*
1148e5487a41SPeter Maydell              * GITS_BASER<n>.TYPE is read-only, so GITS_BASER_RO_MASK
1149e5487a41SPeter Maydell              * ensures we will only see type values corresponding to
1150e5487a41SPeter Maydell              * the values set up in gicv3_its_reset().
1151e5487a41SPeter Maydell              */
1152e5487a41SPeter Maydell             g_assert_not_reached();
11531b08e436SShashi Mallela         }
1154e5487a41SPeter Maydell 
1155e5487a41SPeter Maydell         memset(td, 0, sizeof(*td));
1156e5487a41SPeter Maydell         /*
1157e5487a41SPeter Maydell          * If GITS_BASER<n>.Valid is 0 for any <n> then we will not process
1158e5487a41SPeter Maydell          * interrupts. (GITS_TYPER.HCC is 0 for this implementation, so we
1159e5487a41SPeter Maydell          * do not have a special case where the GITS_BASER<n>.Valid bit is 0
1160e5487a41SPeter Maydell          * for the register corresponding to the Collection table but we
1161e5487a41SPeter Maydell          * still have to process interrupts using non-memory-backed
1162e5487a41SPeter Maydell          * Collection table entries.)
1163da4680ceSPeter Maydell          * The specification makes it UNPREDICTABLE to enable the ITS without
1164da4680ceSPeter Maydell          * marking each BASER<n> as valid. We choose to handle these as if
1165da4680ceSPeter Maydell          * the table was zero-sized, so commands using the table will fail
1166da4680ceSPeter Maydell          * and interrupts requested via GITS_TRANSLATER writes will be ignored.
1167da4680ceSPeter Maydell          * This happens automatically by leaving the num_entries field at
1168da4680ceSPeter Maydell          * zero, which will be caught by the bounds checks we have before
1169da4680ceSPeter Maydell          * every table lookup anyway.
1170e5487a41SPeter Maydell          */
1171da4680ceSPeter Maydell         if (!FIELD_EX64(value, GITS_BASER, VALID)) {
1172e5487a41SPeter Maydell             continue;
1173e5487a41SPeter Maydell         }
1174e5487a41SPeter Maydell         td->page_sz = page_sz;
1175e5487a41SPeter Maydell         td->indirect = FIELD_EX64(value, GITS_BASER, INDIRECT);
11769ae85431SPeter Maydell         td->entry_sz = FIELD_EX64(value, GITS_BASER, ENTRYSIZE) + 1;
1177e5487a41SPeter Maydell         td->base_addr = baser_base_addr(value, page_sz);
1178e5487a41SPeter Maydell         if (!td->indirect) {
117980dcd37fSPeter Maydell             td->num_entries = (num_pages * page_sz) / td->entry_sz;
1180e5487a41SPeter Maydell         } else {
118180dcd37fSPeter Maydell             td->num_entries = (((num_pages * page_sz) /
1182e5487a41SPeter Maydell                                   L1TABLE_ENTRY_SIZE) *
1183e5487a41SPeter Maydell                                  (page_sz / td->entry_sz));
1184e5487a41SPeter Maydell         }
11858b8bb014SPeter Maydell         td->num_entries = MIN(td->num_entries, 1ULL << idbits);
11861b08e436SShashi Mallela     }
11871b08e436SShashi Mallela }
11881b08e436SShashi Mallela 
11891b08e436SShashi Mallela static void extract_cmdq_params(GICv3ITSState *s)
11901b08e436SShashi Mallela {
11911b08e436SShashi Mallela     uint16_t num_pages = 0;
11921b08e436SShashi Mallela     uint64_t value = s->cbaser;
11931b08e436SShashi Mallela 
11941b08e436SShashi Mallela     num_pages = FIELD_EX64(value, GITS_CBASER, SIZE) + 1;
11951b08e436SShashi Mallela 
11961b08e436SShashi Mallela     memset(&s->cq, 0 , sizeof(s->cq));
11971b08e436SShashi Mallela 
1198da4680ceSPeter Maydell     if (FIELD_EX64(value, GITS_CBASER, VALID)) {
119980dcd37fSPeter Maydell         s->cq.num_entries = (num_pages * GITS_PAGE_SIZE_4K) /
12001b08e436SShashi Mallela                              GITS_CMDQ_ENTRY_SIZE;
12011b08e436SShashi Mallela         s->cq.base_addr = FIELD_EX64(value, GITS_CBASER, PHYADDR);
12021b08e436SShashi Mallela         s->cq.base_addr <<= R_GITS_CBASER_PHYADDR_SHIFT;
12031b08e436SShashi Mallela     }
12041b08e436SShashi Mallela }
12051b08e436SShashi Mallela 
12067e062b98SPeter Maydell static MemTxResult gicv3_its_translation_read(void *opaque, hwaddr offset,
12077e062b98SPeter Maydell                                               uint64_t *data, unsigned size,
12087e062b98SPeter Maydell                                               MemTxAttrs attrs)
12097e062b98SPeter Maydell {
12107e062b98SPeter Maydell     /*
12117e062b98SPeter Maydell      * GITS_TRANSLATER is write-only, and all other addresses
12127e062b98SPeter Maydell      * in the interrupt translation space frame are RES0.
12137e062b98SPeter Maydell      */
12147e062b98SPeter Maydell     *data = 0;
12157e062b98SPeter Maydell     return MEMTX_OK;
12167e062b98SPeter Maydell }
12177e062b98SPeter Maydell 
121818f6290aSShashi Mallela static MemTxResult gicv3_its_translation_write(void *opaque, hwaddr offset,
121918f6290aSShashi Mallela                                                uint64_t data, unsigned size,
122018f6290aSShashi Mallela                                                MemTxAttrs attrs)
122118f6290aSShashi Mallela {
1222c694cb4cSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
1223c694cb4cSShashi Mallela     bool result = true;
1224c694cb4cSShashi Mallela 
1225195209d3SPeter Maydell     trace_gicv3_its_translation_write(offset, data, size, attrs.requester_id);
1226195209d3SPeter Maydell 
1227c694cb4cSShashi Mallela     switch (offset) {
1228c694cb4cSShashi Mallela     case GITS_TRANSLATER:
12298d2d6dd9SPeter Maydell         if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
1230b6f96009SPeter Maydell             result = do_process_its_cmd(s, attrs.requester_id, data, NONE);
1231c694cb4cSShashi Mallela         }
1232c694cb4cSShashi Mallela         break;
1233c694cb4cSShashi Mallela     default:
1234c694cb4cSShashi Mallela         break;
1235c694cb4cSShashi Mallela     }
1236c694cb4cSShashi Mallela 
1237c694cb4cSShashi Mallela     if (result) {
123818f6290aSShashi Mallela         return MEMTX_OK;
1239c694cb4cSShashi Mallela     } else {
1240c694cb4cSShashi Mallela         return MEMTX_ERROR;
1241c694cb4cSShashi Mallela     }
124218f6290aSShashi Mallela }
124318f6290aSShashi Mallela 
124418f6290aSShashi Mallela static bool its_writel(GICv3ITSState *s, hwaddr offset,
124518f6290aSShashi Mallela                               uint64_t value, MemTxAttrs attrs)
124618f6290aSShashi Mallela {
124718f6290aSShashi Mallela     bool result = true;
12481b08e436SShashi Mallela     int index;
124918f6290aSShashi Mallela 
12501b08e436SShashi Mallela     switch (offset) {
12511b08e436SShashi Mallela     case GITS_CTLR:
12522f459cd1SShashi Mallela         if (value & R_GITS_CTLR_ENABLED_MASK) {
12538d2d6dd9SPeter Maydell             s->ctlr |= R_GITS_CTLR_ENABLED_MASK;
12541b08e436SShashi Mallela             extract_table_params(s);
12551b08e436SShashi Mallela             extract_cmdq_params(s);
12567eca39e0SShashi Mallela             process_cmdq(s);
12572f459cd1SShashi Mallela         } else {
12588d2d6dd9SPeter Maydell             s->ctlr &= ~R_GITS_CTLR_ENABLED_MASK;
12591b08e436SShashi Mallela         }
12601b08e436SShashi Mallela         break;
12611b08e436SShashi Mallela     case GITS_CBASER:
12621b08e436SShashi Mallela         /*
12631b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
12641b08e436SShashi Mallela          *                 already enabled
12651b08e436SShashi Mallela          */
12668d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
12671b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 0, 32, value);
12681b08e436SShashi Mallela             s->creadr = 0;
12691b08e436SShashi Mallela         }
12701b08e436SShashi Mallela         break;
12711b08e436SShashi Mallela     case GITS_CBASER + 4:
12721b08e436SShashi Mallela         /*
12731b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
12741b08e436SShashi Mallela          *                 already enabled
12751b08e436SShashi Mallela          */
12768d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
12771b08e436SShashi Mallela             s->cbaser = deposit64(s->cbaser, 32, 32, value);
12781b08e436SShashi Mallela             s->creadr = 0;
12791b08e436SShashi Mallela         }
12801b08e436SShashi Mallela         break;
12811b08e436SShashi Mallela     case GITS_CWRITER:
12821b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 0, 32,
12831b08e436SShashi Mallela                                (value & ~R_GITS_CWRITER_RETRY_MASK));
12847eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
12857eca39e0SShashi Mallela             process_cmdq(s);
12867eca39e0SShashi Mallela         }
12871b08e436SShashi Mallela         break;
12881b08e436SShashi Mallela     case GITS_CWRITER + 4:
12891b08e436SShashi Mallela         s->cwriter = deposit64(s->cwriter, 32, 32, value);
12901b08e436SShashi Mallela         break;
12911b08e436SShashi Mallela     case GITS_CREADR:
12921b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
12931b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 0, 32,
12941b08e436SShashi Mallela                                   (value & ~R_GITS_CREADR_STALLED_MASK));
12951b08e436SShashi Mallela         } else {
12961b08e436SShashi Mallela             /* RO register, ignore the write */
12971b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
12981b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
12991b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
13001b08e436SShashi Mallela         }
13011b08e436SShashi Mallela         break;
13021b08e436SShashi Mallela     case GITS_CREADR + 4:
13031b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
13041b08e436SShashi Mallela             s->creadr = deposit64(s->creadr, 32, 32, value);
13051b08e436SShashi Mallela         } else {
13061b08e436SShashi Mallela             /* RO register, ignore the write */
13071b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
13081b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
13091b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
13101b08e436SShashi Mallela         }
13111b08e436SShashi Mallela         break;
13121b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
13131b08e436SShashi Mallela         /*
13141b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
13151b08e436SShashi Mallela          *                 already enabled
13161b08e436SShashi Mallela          */
13178d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
13181b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
13191b08e436SShashi Mallela 
13200ffe88e6SPeter Maydell             if (s->baser[index] == 0) {
13210ffe88e6SPeter Maydell                 /* Unimplemented GITS_BASERn: RAZ/WI */
13220ffe88e6SPeter Maydell                 break;
13230ffe88e6SPeter Maydell             }
13241b08e436SShashi Mallela             if (offset & 7) {
13251b08e436SShashi Mallela                 value <<= 32;
13261b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
13271b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(0, 32);
13281b08e436SShashi Mallela                 s->baser[index] |= value;
13291b08e436SShashi Mallela             } else {
13301b08e436SShashi Mallela                 value &= ~GITS_BASER_RO_MASK;
13311b08e436SShashi Mallela                 s->baser[index] &= GITS_BASER_RO_MASK | MAKE_64BIT_MASK(32, 32);
13321b08e436SShashi Mallela                 s->baser[index] |= value;
13331b08e436SShashi Mallela             }
13341b08e436SShashi Mallela         }
13351b08e436SShashi Mallela         break;
13361b08e436SShashi Mallela     case GITS_IIDR:
13371b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
13381b08e436SShashi Mallela         /* RO registers, ignore the write */
13391b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
13401b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
13411b08e436SShashi Mallela                       TARGET_FMT_plx "\n", __func__, offset);
13421b08e436SShashi Mallela         break;
13431b08e436SShashi Mallela     default:
13441b08e436SShashi Mallela         result = false;
13451b08e436SShashi Mallela         break;
13461b08e436SShashi Mallela     }
134718f6290aSShashi Mallela     return result;
134818f6290aSShashi Mallela }
134918f6290aSShashi Mallela 
135018f6290aSShashi Mallela static bool its_readl(GICv3ITSState *s, hwaddr offset,
135118f6290aSShashi Mallela                              uint64_t *data, MemTxAttrs attrs)
135218f6290aSShashi Mallela {
135318f6290aSShashi Mallela     bool result = true;
13541b08e436SShashi Mallela     int index;
135518f6290aSShashi Mallela 
13561b08e436SShashi Mallela     switch (offset) {
13571b08e436SShashi Mallela     case GITS_CTLR:
13581b08e436SShashi Mallela         *data = s->ctlr;
13591b08e436SShashi Mallela         break;
13601b08e436SShashi Mallela     case GITS_IIDR:
13611b08e436SShashi Mallela         *data = gicv3_iidr();
13621b08e436SShashi Mallela         break;
13631b08e436SShashi Mallela     case GITS_IDREGS ... GITS_IDREGS + 0x2f:
13641b08e436SShashi Mallela         /* ID registers */
136550a3a309SPeter Maydell         *data = gicv3_idreg(offset - GITS_IDREGS, GICV3_PIDR0_ITS);
13661b08e436SShashi Mallela         break;
13671b08e436SShashi Mallela     case GITS_TYPER:
13681b08e436SShashi Mallela         *data = extract64(s->typer, 0, 32);
13691b08e436SShashi Mallela         break;
13701b08e436SShashi Mallela     case GITS_TYPER + 4:
13711b08e436SShashi Mallela         *data = extract64(s->typer, 32, 32);
13721b08e436SShashi Mallela         break;
13731b08e436SShashi Mallela     case GITS_CBASER:
13741b08e436SShashi Mallela         *data = extract64(s->cbaser, 0, 32);
13751b08e436SShashi Mallela         break;
13761b08e436SShashi Mallela     case GITS_CBASER + 4:
13771b08e436SShashi Mallela         *data = extract64(s->cbaser, 32, 32);
13781b08e436SShashi Mallela         break;
13791b08e436SShashi Mallela     case GITS_CREADR:
13801b08e436SShashi Mallela         *data = extract64(s->creadr, 0, 32);
13811b08e436SShashi Mallela         break;
13821b08e436SShashi Mallela     case GITS_CREADR + 4:
13831b08e436SShashi Mallela         *data = extract64(s->creadr, 32, 32);
13841b08e436SShashi Mallela         break;
13851b08e436SShashi Mallela     case GITS_CWRITER:
13861b08e436SShashi Mallela         *data = extract64(s->cwriter, 0, 32);
13871b08e436SShashi Mallela         break;
13881b08e436SShashi Mallela     case GITS_CWRITER + 4:
13891b08e436SShashi Mallela         *data = extract64(s->cwriter, 32, 32);
13901b08e436SShashi Mallela         break;
13911b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
13921b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
13931b08e436SShashi Mallela         if (offset & 7) {
13941b08e436SShashi Mallela             *data = extract64(s->baser[index], 32, 32);
13951b08e436SShashi Mallela         } else {
13961b08e436SShashi Mallela             *data = extract64(s->baser[index], 0, 32);
13971b08e436SShashi Mallela         }
13981b08e436SShashi Mallela         break;
13991b08e436SShashi Mallela     default:
14001b08e436SShashi Mallela         result = false;
14011b08e436SShashi Mallela         break;
14021b08e436SShashi Mallela     }
140318f6290aSShashi Mallela     return result;
140418f6290aSShashi Mallela }
140518f6290aSShashi Mallela 
140618f6290aSShashi Mallela static bool its_writell(GICv3ITSState *s, hwaddr offset,
140718f6290aSShashi Mallela                                uint64_t value, MemTxAttrs attrs)
140818f6290aSShashi Mallela {
140918f6290aSShashi Mallela     bool result = true;
14101b08e436SShashi Mallela     int index;
141118f6290aSShashi Mallela 
14121b08e436SShashi Mallela     switch (offset) {
14131b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
14141b08e436SShashi Mallela         /*
14151b08e436SShashi Mallela          * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
14161b08e436SShashi Mallela          *                 already enabled
14171b08e436SShashi Mallela          */
14188d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
14191b08e436SShashi Mallela             index = (offset - GITS_BASER) / 8;
14200ffe88e6SPeter Maydell             if (s->baser[index] == 0) {
14210ffe88e6SPeter Maydell                 /* Unimplemented GITS_BASERn: RAZ/WI */
14220ffe88e6SPeter Maydell                 break;
14230ffe88e6SPeter Maydell             }
14241b08e436SShashi Mallela             s->baser[index] &= GITS_BASER_RO_MASK;
14251b08e436SShashi Mallela             s->baser[index] |= (value & ~GITS_BASER_RO_MASK);
14261b08e436SShashi Mallela         }
14271b08e436SShashi Mallela         break;
14281b08e436SShashi Mallela     case GITS_CBASER:
14291b08e436SShashi Mallela         /*
14301b08e436SShashi Mallela          * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
14311b08e436SShashi Mallela          *                 already enabled
14321b08e436SShashi Mallela          */
14338d2d6dd9SPeter Maydell         if (!(s->ctlr & R_GITS_CTLR_ENABLED_MASK)) {
14341b08e436SShashi Mallela             s->cbaser = value;
14351b08e436SShashi Mallela             s->creadr = 0;
14361b08e436SShashi Mallela         }
14371b08e436SShashi Mallela         break;
14381b08e436SShashi Mallela     case GITS_CWRITER:
14391b08e436SShashi Mallela         s->cwriter = value & ~R_GITS_CWRITER_RETRY_MASK;
14407eca39e0SShashi Mallela         if (s->cwriter != s->creadr) {
14417eca39e0SShashi Mallela             process_cmdq(s);
14427eca39e0SShashi Mallela         }
14431b08e436SShashi Mallela         break;
14441b08e436SShashi Mallela     case GITS_CREADR:
14451b08e436SShashi Mallela         if (s->gicv3->gicd_ctlr & GICD_CTLR_DS) {
14461b08e436SShashi Mallela             s->creadr = value & ~R_GITS_CREADR_STALLED_MASK;
14471b08e436SShashi Mallela         } else {
14481b08e436SShashi Mallela             /* RO register, ignore the write */
14491b08e436SShashi Mallela             qemu_log_mask(LOG_GUEST_ERROR,
14501b08e436SShashi Mallela                           "%s: invalid guest write to RO register at offset "
14511b08e436SShashi Mallela                           TARGET_FMT_plx "\n", __func__, offset);
14521b08e436SShashi Mallela         }
14531b08e436SShashi Mallela         break;
14541b08e436SShashi Mallela     case GITS_TYPER:
14551b08e436SShashi Mallela         /* RO registers, ignore the write */
14561b08e436SShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
14571b08e436SShashi Mallela                       "%s: invalid guest write to RO register at offset "
14581b08e436SShashi Mallela                       TARGET_FMT_plx "\n", __func__, offset);
14591b08e436SShashi Mallela         break;
14601b08e436SShashi Mallela     default:
14611b08e436SShashi Mallela         result = false;
14621b08e436SShashi Mallela         break;
14631b08e436SShashi Mallela     }
146418f6290aSShashi Mallela     return result;
146518f6290aSShashi Mallela }
146618f6290aSShashi Mallela 
146718f6290aSShashi Mallela static bool its_readll(GICv3ITSState *s, hwaddr offset,
146818f6290aSShashi Mallela                               uint64_t *data, MemTxAttrs attrs)
146918f6290aSShashi Mallela {
147018f6290aSShashi Mallela     bool result = true;
14711b08e436SShashi Mallela     int index;
147218f6290aSShashi Mallela 
14731b08e436SShashi Mallela     switch (offset) {
14741b08e436SShashi Mallela     case GITS_TYPER:
14751b08e436SShashi Mallela         *data = s->typer;
14761b08e436SShashi Mallela         break;
14771b08e436SShashi Mallela     case GITS_BASER ... GITS_BASER + 0x3f:
14781b08e436SShashi Mallela         index = (offset - GITS_BASER) / 8;
14791b08e436SShashi Mallela         *data = s->baser[index];
14801b08e436SShashi Mallela         break;
14811b08e436SShashi Mallela     case GITS_CBASER:
14821b08e436SShashi Mallela         *data = s->cbaser;
14831b08e436SShashi Mallela         break;
14841b08e436SShashi Mallela     case GITS_CREADR:
14851b08e436SShashi Mallela         *data = s->creadr;
14861b08e436SShashi Mallela         break;
14871b08e436SShashi Mallela     case GITS_CWRITER:
14881b08e436SShashi Mallela         *data = s->cwriter;
14891b08e436SShashi Mallela         break;
14901b08e436SShashi Mallela     default:
14911b08e436SShashi Mallela         result = false;
14921b08e436SShashi Mallela         break;
14931b08e436SShashi Mallela     }
149418f6290aSShashi Mallela     return result;
149518f6290aSShashi Mallela }
149618f6290aSShashi Mallela 
149718f6290aSShashi Mallela static MemTxResult gicv3_its_read(void *opaque, hwaddr offset, uint64_t *data,
149818f6290aSShashi Mallela                                   unsigned size, MemTxAttrs attrs)
149918f6290aSShashi Mallela {
150018f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
150118f6290aSShashi Mallela     bool result;
150218f6290aSShashi Mallela 
150318f6290aSShashi Mallela     switch (size) {
150418f6290aSShashi Mallela     case 4:
150518f6290aSShashi Mallela         result = its_readl(s, offset, data, attrs);
150618f6290aSShashi Mallela         break;
150718f6290aSShashi Mallela     case 8:
150818f6290aSShashi Mallela         result = its_readll(s, offset, data, attrs);
150918f6290aSShashi Mallela         break;
151018f6290aSShashi Mallela     default:
151118f6290aSShashi Mallela         result = false;
151218f6290aSShashi Mallela         break;
151318f6290aSShashi Mallela     }
151418f6290aSShashi Mallela 
151518f6290aSShashi Mallela     if (!result) {
151618f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
151718f6290aSShashi Mallela                       "%s: invalid guest read at offset " TARGET_FMT_plx
151818f6290aSShashi Mallela                       " size %u\n", __func__, offset, size);
1519195209d3SPeter Maydell         trace_gicv3_its_badread(offset, size);
152018f6290aSShashi Mallela         /*
152118f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
152218f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
152318f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
152418f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
152518f6290aSShashi Mallela          */
152618f6290aSShashi Mallela         *data = 0;
1527195209d3SPeter Maydell     } else {
1528195209d3SPeter Maydell         trace_gicv3_its_read(offset, *data, size);
152918f6290aSShashi Mallela     }
153018f6290aSShashi Mallela     return MEMTX_OK;
153118f6290aSShashi Mallela }
153218f6290aSShashi Mallela 
153318f6290aSShashi Mallela static MemTxResult gicv3_its_write(void *opaque, hwaddr offset, uint64_t data,
153418f6290aSShashi Mallela                                    unsigned size, MemTxAttrs attrs)
153518f6290aSShashi Mallela {
153618f6290aSShashi Mallela     GICv3ITSState *s = (GICv3ITSState *)opaque;
153718f6290aSShashi Mallela     bool result;
153818f6290aSShashi Mallela 
153918f6290aSShashi Mallela     switch (size) {
154018f6290aSShashi Mallela     case 4:
154118f6290aSShashi Mallela         result = its_writel(s, offset, data, attrs);
154218f6290aSShashi Mallela         break;
154318f6290aSShashi Mallela     case 8:
154418f6290aSShashi Mallela         result = its_writell(s, offset, data, attrs);
154518f6290aSShashi Mallela         break;
154618f6290aSShashi Mallela     default:
154718f6290aSShashi Mallela         result = false;
154818f6290aSShashi Mallela         break;
154918f6290aSShashi Mallela     }
155018f6290aSShashi Mallela 
155118f6290aSShashi Mallela     if (!result) {
155218f6290aSShashi Mallela         qemu_log_mask(LOG_GUEST_ERROR,
155318f6290aSShashi Mallela                       "%s: invalid guest write at offset " TARGET_FMT_plx
155418f6290aSShashi Mallela                       " size %u\n", __func__, offset, size);
1555195209d3SPeter Maydell         trace_gicv3_its_badwrite(offset, data, size);
155618f6290aSShashi Mallela         /*
155718f6290aSShashi Mallela          * The spec requires that reserved registers are RAZ/WI;
155818f6290aSShashi Mallela          * so use false returns from leaf functions as a way to
155918f6290aSShashi Mallela          * trigger the guest-error logging but don't return it to
156018f6290aSShashi Mallela          * the caller, or we'll cause a spurious guest data abort.
156118f6290aSShashi Mallela          */
1562195209d3SPeter Maydell     } else {
1563195209d3SPeter Maydell         trace_gicv3_its_write(offset, data, size);
156418f6290aSShashi Mallela     }
156518f6290aSShashi Mallela     return MEMTX_OK;
156618f6290aSShashi Mallela }
156718f6290aSShashi Mallela 
156818f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_control_ops = {
156918f6290aSShashi Mallela     .read_with_attrs = gicv3_its_read,
157018f6290aSShashi Mallela     .write_with_attrs = gicv3_its_write,
157118f6290aSShashi Mallela     .valid.min_access_size = 4,
157218f6290aSShashi Mallela     .valid.max_access_size = 8,
157318f6290aSShashi Mallela     .impl.min_access_size = 4,
157418f6290aSShashi Mallela     .impl.max_access_size = 8,
157518f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
157618f6290aSShashi Mallela };
157718f6290aSShashi Mallela 
157818f6290aSShashi Mallela static const MemoryRegionOps gicv3_its_translation_ops = {
15797e062b98SPeter Maydell     .read_with_attrs = gicv3_its_translation_read,
158018f6290aSShashi Mallela     .write_with_attrs = gicv3_its_translation_write,
158118f6290aSShashi Mallela     .valid.min_access_size = 2,
158218f6290aSShashi Mallela     .valid.max_access_size = 4,
158318f6290aSShashi Mallela     .impl.min_access_size = 2,
158418f6290aSShashi Mallela     .impl.max_access_size = 4,
158518f6290aSShashi Mallela     .endianness = DEVICE_NATIVE_ENDIAN,
158618f6290aSShashi Mallela };
158718f6290aSShashi Mallela 
158818f6290aSShashi Mallela static void gicv3_arm_its_realize(DeviceState *dev, Error **errp)
158918f6290aSShashi Mallela {
159018f6290aSShashi Mallela     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
159118f6290aSShashi Mallela     int i;
159218f6290aSShashi Mallela 
159318f6290aSShashi Mallela     for (i = 0; i < s->gicv3->num_cpu; i++) {
159418f6290aSShashi Mallela         if (!(s->gicv3->cpu[i].gicr_typer & GICR_TYPER_PLPIS)) {
159518f6290aSShashi Mallela             error_setg(errp, "Physical LPI not supported by CPU %d", i);
159618f6290aSShashi Mallela             return;
159718f6290aSShashi Mallela         }
159818f6290aSShashi Mallela     }
159918f6290aSShashi Mallela 
160018f6290aSShashi Mallela     gicv3_its_init_mmio(s, &gicv3_its_control_ops, &gicv3_its_translation_ops);
160118f6290aSShashi Mallela 
160218f6290aSShashi Mallela     /* set the ITS default features supported */
1603764d6ba1SPeter Maydell     s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL, 1);
160418f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, ITT_ENTRY_SIZE,
160518f6290aSShashi Mallela                           ITS_ITT_ENTRY_SIZE - 1);
160618f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, IDBITS, ITS_IDBITS);
160718f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, DEVBITS, ITS_DEVBITS);
160818f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIL, 1);
160918f6290aSShashi Mallela     s->typer = FIELD_DP64(s->typer, GITS_TYPER, CIDBITS, ITS_CIDBITS);
161018f6290aSShashi Mallela }
161118f6290aSShashi Mallela 
161218f6290aSShashi Mallela static void gicv3_its_reset(DeviceState *dev)
161318f6290aSShashi Mallela {
161418f6290aSShashi Mallela     GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev);
161518f6290aSShashi Mallela     GICv3ITSClass *c = ARM_GICV3_ITS_GET_CLASS(s);
161618f6290aSShashi Mallela 
161718f6290aSShashi Mallela     c->parent_reset(dev);
161818f6290aSShashi Mallela 
161918f6290aSShashi Mallela     /* Quiescent bit reset to 1 */
162018f6290aSShashi Mallela     s->ctlr = FIELD_DP32(s->ctlr, GITS_CTLR, QUIESCENT, 1);
162118f6290aSShashi Mallela 
162218f6290aSShashi Mallela     /*
162318f6290aSShashi Mallela      * setting GITS_BASER0.Type = 0b001 (Device)
162418f6290aSShashi Mallela      *         GITS_BASER1.Type = 0b100 (Collection Table)
162550d84584SPeter Maydell      *         GITS_BASER2.Type = 0b010 (vPE) for GICv4 and later
162618f6290aSShashi Mallela      *         GITS_BASER<n>.Type,where n = 3 to 7 are 0b00 (Unimplemented)
162718f6290aSShashi Mallela      *         GITS_BASER<0,1>.Page_Size = 64KB
162818f6290aSShashi Mallela      * and default translation table entry size to 16 bytes
162918f6290aSShashi Mallela      */
163018f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, TYPE,
163118f6290aSShashi Mallela                              GITS_BASER_TYPE_DEVICE);
163218f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, PAGESIZE,
163318f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
163418f6290aSShashi Mallela     s->baser[0] = FIELD_DP64(s->baser[0], GITS_BASER, ENTRYSIZE,
163518f6290aSShashi Mallela                              GITS_DTE_SIZE - 1);
163618f6290aSShashi Mallela 
163718f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, TYPE,
163818f6290aSShashi Mallela                              GITS_BASER_TYPE_COLLECTION);
163918f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, PAGESIZE,
164018f6290aSShashi Mallela                              GITS_BASER_PAGESIZE_64K);
164118f6290aSShashi Mallela     s->baser[1] = FIELD_DP64(s->baser[1], GITS_BASER, ENTRYSIZE,
164218f6290aSShashi Mallela                              GITS_CTE_SIZE - 1);
164350d84584SPeter Maydell 
164450d84584SPeter Maydell     if (its_feature_virtual(s)) {
164550d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, TYPE,
164650d84584SPeter Maydell                                  GITS_BASER_TYPE_VPE);
164750d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, PAGESIZE,
164850d84584SPeter Maydell                                  GITS_BASER_PAGESIZE_64K);
164950d84584SPeter Maydell         s->baser[2] = FIELD_DP64(s->baser[2], GITS_BASER, ENTRYSIZE,
165050d84584SPeter Maydell                                  GITS_VPE_SIZE - 1);
165150d84584SPeter Maydell     }
165218f6290aSShashi Mallela }
165318f6290aSShashi Mallela 
16541b08e436SShashi Mallela static void gicv3_its_post_load(GICv3ITSState *s)
16551b08e436SShashi Mallela {
16568d2d6dd9SPeter Maydell     if (s->ctlr & R_GITS_CTLR_ENABLED_MASK) {
16571b08e436SShashi Mallela         extract_table_params(s);
16581b08e436SShashi Mallela         extract_cmdq_params(s);
16591b08e436SShashi Mallela     }
16601b08e436SShashi Mallela }
16611b08e436SShashi Mallela 
166218f6290aSShashi Mallela static Property gicv3_its_props[] = {
166318f6290aSShashi Mallela     DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState, gicv3, "arm-gicv3",
166418f6290aSShashi Mallela                      GICv3State *),
166518f6290aSShashi Mallela     DEFINE_PROP_END_OF_LIST(),
166618f6290aSShashi Mallela };
166718f6290aSShashi Mallela 
166818f6290aSShashi Mallela static void gicv3_its_class_init(ObjectClass *klass, void *data)
166918f6290aSShashi Mallela {
167018f6290aSShashi Mallela     DeviceClass *dc = DEVICE_CLASS(klass);
167118f6290aSShashi Mallela     GICv3ITSClass *ic = ARM_GICV3_ITS_CLASS(klass);
16721b08e436SShashi Mallela     GICv3ITSCommonClass *icc = ARM_GICV3_ITS_COMMON_CLASS(klass);
167318f6290aSShashi Mallela 
167418f6290aSShashi Mallela     dc->realize = gicv3_arm_its_realize;
167518f6290aSShashi Mallela     device_class_set_props(dc, gicv3_its_props);
167618f6290aSShashi Mallela     device_class_set_parent_reset(dc, gicv3_its_reset, &ic->parent_reset);
16771b08e436SShashi Mallela     icc->post_load = gicv3_its_post_load;
167818f6290aSShashi Mallela }
167918f6290aSShashi Mallela 
168018f6290aSShashi Mallela static const TypeInfo gicv3_its_info = {
168118f6290aSShashi Mallela     .name = TYPE_ARM_GICV3_ITS,
168218f6290aSShashi Mallela     .parent = TYPE_ARM_GICV3_ITS_COMMON,
168318f6290aSShashi Mallela     .instance_size = sizeof(GICv3ITSState),
168418f6290aSShashi Mallela     .class_init = gicv3_its_class_init,
168518f6290aSShashi Mallela     .class_size = sizeof(GICv3ITSClass),
168618f6290aSShashi Mallela };
168718f6290aSShashi Mallela 
168818f6290aSShashi Mallela static void gicv3_its_register_types(void)
168918f6290aSShashi Mallela {
169018f6290aSShashi Mallela     type_register_static(&gicv3_its_info);
169118f6290aSShashi Mallela }
169218f6290aSShashi Mallela 
169318f6290aSShashi Mallela type_init(gicv3_its_register_types)
1694