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