[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PULL 35/38] hw/intc/arm_gicv3_its: Factor out "find address of table en
|
From: |
Peter Maydell |
|
Subject: |
[PULL 35/38] hw/intc/arm_gicv3_its: Factor out "find address of table entry" code |
|
Date: |
Thu, 20 Jan 2022 12:36:27 +0000 |
The ITS has several tables which all share a similar format,
described by the TableDesc struct: the guest may configure them
to be a single-level table or a two-level table. Currently we
open-code the process of finding the table entry in all the
functions which read or write the device table or the collection
table. Factor out the "get the address of the table entry"
logic into a new function, so that the code which needs to
read or write a table entry only needs to call table_entry_addr()
and then perform a suitable load or store to that address.
Note that the error handling is slightly complicated because
we want to handle two cases differently:
* failure to read the L1 table entry should end up causing
a command stall, like other kinds of DMA error
* an L1 table entry that says there is no L2 table for this
index (ie whose valid bit is 0) must result in us treating
the table entry as not-valid on read, and discarding
writes (this is mandated by the spec)
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Message-id: 20220111171048.3545974-12-peter.maydell@linaro.org
---
hw/intc/arm_gicv3_its.c | 212 +++++++++++++---------------------------
1 file changed, 70 insertions(+), 142 deletions(-)
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c
index 917201c148f..985e316eda9 100644
--- a/hw/intc/arm_gicv3_its.c
+++ b/hw/intc/arm_gicv3_its.c
@@ -83,44 +83,62 @@ static uint64_t baser_base_addr(uint64_t value, uint32_t
page_sz)
return result;
}
+static uint64_t table_entry_addr(GICv3ITSState *s, TableDesc *td,
+ uint32_t idx, MemTxResult *res)
+{
+ /*
+ * Given a TableDesc describing one of the ITS in-guest-memory
+ * tables and an index into it, return the guest address
+ * corresponding to that table entry.
+ * If there was a memory error reading the L1 table of an
+ * indirect table, *res is set accordingly, and we return -1.
+ * If the L1 table entry is marked not valid, we return -1 with
+ * *res set to MEMTX_OK.
+ *
+ * The specification defines the format of level 1 entries of a
+ * 2-level table, but the format of level 2 entries and the format
+ * of flat-mapped tables is IMPDEF.
+ */
+ AddressSpace *as = &s->gicv3->dma_as;
+ uint32_t l2idx;
+ uint64_t l2;
+ uint32_t num_l2_entries;
+
+ *res = MEMTX_OK;
+
+ if (!td->indirect) {
+ /* Single level table */
+ return td->base_addr + idx * td->entry_sz;
+ }
+
+ /* Two level table */
+ l2idx = idx / (td->page_sz / L1TABLE_ENTRY_SIZE);
+
+ l2 = address_space_ldq_le(as,
+ td->base_addr + (l2idx * L1TABLE_ENTRY_SIZE),
+ MEMTXATTRS_UNSPECIFIED, res);
+ if (*res != MEMTX_OK) {
+ return -1;
+ }
+ if (!(l2 & L2_TABLE_VALID_MASK)) {
+ return -1;
+ }
+
+ num_l2_entries = td->page_sz / td->entry_sz;
+ return (l2 & ((1ULL << 51) - 1)) + (idx % num_l2_entries) * td->entry_sz;
+}
+
static bool get_cte(GICv3ITSState *s, uint16_t icid, uint64_t *cte,
MemTxResult *res)
{
AddressSpace *as = &s->gicv3->dma_as;
- uint64_t l2t_addr;
- uint64_t value;
- bool valid_l2t;
- uint32_t l2t_id;
- uint32_t num_l2_entries;
+ uint64_t entry_addr = table_entry_addr(s, &s->ct, icid, res);
- if (s->ct.indirect) {
- l2t_id = icid / (s->ct.page_sz / L1TABLE_ENTRY_SIZE);
-
- value = address_space_ldq_le(as,
- s->ct.base_addr +
- (l2t_id * L1TABLE_ENTRY_SIZE),
- MEMTXATTRS_UNSPECIFIED, res);
-
- if (*res == MEMTX_OK) {
- valid_l2t = (value & L2_TABLE_VALID_MASK) != 0;
-
- if (valid_l2t) {
- num_l2_entries = s->ct.page_sz / s->ct.entry_sz;
-
- l2t_addr = value & ((1ULL << 51) - 1);
-
- *cte = address_space_ldq_le(as, l2t_addr +
- ((icid % num_l2_entries) * GITS_CTE_SIZE),
- MEMTXATTRS_UNSPECIFIED, res);
- }
- }
- } else {
- /* Flat level table */
- *cte = address_space_ldq_le(as, s->ct.base_addr +
- (icid * GITS_CTE_SIZE),
- MEMTXATTRS_UNSPECIFIED, res);
+ if (entry_addr == -1) {
+ return false; /* not valid */
}
+ *cte = address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, res);
return FIELD_EX64(*cte, CTE, VALID);
}
@@ -189,41 +207,12 @@ static bool get_ite(GICv3ITSState *s, uint32_t eventid,
uint64_t dte,
static uint64_t get_dte(GICv3ITSState *s, uint32_t devid, MemTxResult *res)
{
AddressSpace *as = &s->gicv3->dma_as;
- uint64_t l2t_addr;
- uint64_t value;
- bool valid_l2t;
- uint32_t l2t_id;
- uint32_t num_l2_entries;
+ uint64_t entry_addr = table_entry_addr(s, &s->dt, devid, res);
- if (s->dt.indirect) {
- l2t_id = devid / (s->dt.page_sz / L1TABLE_ENTRY_SIZE);
-
- value = address_space_ldq_le(as,
- s->dt.base_addr +
- (l2t_id * L1TABLE_ENTRY_SIZE),
- MEMTXATTRS_UNSPECIFIED, res);
-
- if (*res == MEMTX_OK) {
- valid_l2t = (value & L2_TABLE_VALID_MASK) != 0;
-
- if (valid_l2t) {
- num_l2_entries = s->dt.page_sz / s->dt.entry_sz;
-
- l2t_addr = value & ((1ULL << 51) - 1);
-
- value = address_space_ldq_le(as, l2t_addr +
- ((devid % num_l2_entries) * GITS_DTE_SIZE),
- MEMTXATTRS_UNSPECIFIED, res);
- }
- }
- } else {
- /* Flat level table */
- value = address_space_ldq_le(as, s->dt.base_addr +
- (devid * GITS_DTE_SIZE),
- MEMTXATTRS_UNSPECIFIED, res);
+ if (entry_addr == -1) {
+ return 0; /* a DTE entry with the Valid bit clear */
}
-
- return value;
+ return address_space_ldq_le(as, entry_addr, MEMTXATTRS_UNSPECIFIED, res);
}
/*
@@ -426,11 +415,7 @@ static bool update_cte(GICv3ITSState *s, uint16_t icid,
bool valid,
uint64_t rdbase)
{
AddressSpace *as = &s->gicv3->dma_as;
- uint64_t value;
- uint64_t l2t_addr;
- bool valid_l2t;
- uint32_t l2t_id;
- uint32_t num_l2_entries;
+ uint64_t entry_addr;
uint64_t cte = 0;
MemTxResult res = MEMTX_OK;
@@ -444,44 +429,18 @@ static bool update_cte(GICv3ITSState *s, uint16_t icid,
bool valid,
cte = FIELD_DP64(cte, CTE, RDBASE, rdbase);
}
- /*
- * The specification defines the format of level 1 entries of a
- * 2-level table, but the format of level 2 entries and the format
- * of flat-mapped tables is IMPDEF.
- */
- if (s->ct.indirect) {
- l2t_id = icid / (s->ct.page_sz / L1TABLE_ENTRY_SIZE);
-
- value = address_space_ldq_le(as,
- s->ct.base_addr +
- (l2t_id * L1TABLE_ENTRY_SIZE),
- MEMTXATTRS_UNSPECIFIED, &res);
-
- if (res != MEMTX_OK) {
- return false;
- }
-
- valid_l2t = (value & L2_TABLE_VALID_MASK) != 0;
-
- if (valid_l2t) {
- num_l2_entries = s->ct.page_sz / s->ct.entry_sz;
-
- l2t_addr = value & ((1ULL << 51) - 1);
-
- address_space_stq_le(as, l2t_addr +
- ((icid % num_l2_entries) * GITS_CTE_SIZE),
- cte, MEMTXATTRS_UNSPECIFIED, &res);
- }
- } else {
- /* Flat level table */
- address_space_stq_le(as, s->ct.base_addr + (icid * GITS_CTE_SIZE),
- cte, MEMTXATTRS_UNSPECIFIED, &res);
- }
+ entry_addr = table_entry_addr(s, &s->ct, icid, &res);
if (res != MEMTX_OK) {
+ /* memory access error: stall */
return false;
- } else {
+ }
+ if (entry_addr == -1) {
+ /* No L2 table for this index: discard write and continue */
return true;
}
+
+ address_space_stq_le(as, entry_addr, cte, MEMTXATTRS_UNSPECIFIED, &res);
+ return res == MEMTX_OK;
}
static ItsCmdResult process_mapc(GICv3ITSState *s, uint32_t offset)
@@ -529,11 +488,7 @@ static bool update_dte(GICv3ITSState *s, uint32_t devid,
bool valid,
uint8_t size, uint64_t itt_addr)
{
AddressSpace *as = &s->gicv3->dma_as;
- uint64_t value;
- uint64_t l2t_addr;
- bool valid_l2t;
- uint32_t l2t_id;
- uint32_t num_l2_entries;
+ uint64_t entry_addr;
uint64_t dte = 0;
MemTxResult res = MEMTX_OK;
@@ -548,44 +503,17 @@ static bool update_dte(GICv3ITSState *s, uint32_t devid,
bool valid,
return true;
}
- /*
- * The specification defines the format of level 1 entries of a
- * 2-level table, but the format of level 2 entries and the format
- * of flat-mapped tables is IMPDEF.
- */
- if (s->dt.indirect) {
- l2t_id = devid / (s->dt.page_sz / L1TABLE_ENTRY_SIZE);
-
- value = address_space_ldq_le(as,
- s->dt.base_addr +
- (l2t_id * L1TABLE_ENTRY_SIZE),
- MEMTXATTRS_UNSPECIFIED, &res);
-
- if (res != MEMTX_OK) {
- return false;
- }
-
- valid_l2t = (value & L2_TABLE_VALID_MASK) != 0;
-
- if (valid_l2t) {
- num_l2_entries = s->dt.page_sz / s->dt.entry_sz;
-
- l2t_addr = value & ((1ULL << 51) - 1);
-
- address_space_stq_le(as, l2t_addr +
- ((devid % num_l2_entries) * GITS_DTE_SIZE),
- dte, MEMTXATTRS_UNSPECIFIED, &res);
- }
- } else {
- /* Flat level table */
- address_space_stq_le(as, s->dt.base_addr + (devid * GITS_DTE_SIZE),
- dte, MEMTXATTRS_UNSPECIFIED, &res);
- }
+ entry_addr = table_entry_addr(s, &s->dt, devid, &res);
if (res != MEMTX_OK) {
+ /* memory access error: stall */
return false;
- } else {
+ }
+ if (entry_addr == -1) {
+ /* No L2 table for this index: discard write and continue */
return true;
}
+ address_space_stq_le(as, entry_addr, dte, MEMTXATTRS_UNSPECIFIED, &res);
+ return res == MEMTX_OK;
}
static ItsCmdResult process_mapd(GICv3ITSState *s, uint64_t value,
--
2.25.1
- [PULL 00/38] target-arm queue, Peter Maydell, 2022/01/20
- [PULL 05/38] hw/arm/virt: Support CPU cluster on ARM virt machine, Peter Maydell, 2022/01/20
- [PULL 01/38] hw/arm/virt: KVM: Enable PAuth when supported by the host, Peter Maydell, 2022/01/20
- [PULL 09/38] hw/acpi/aml-build: Support cluster level in PPTT generation, Peter Maydell, 2022/01/20
- [PULL 17/38] hw/arm/virt: Add a control for the the highmem redistributors, Peter Maydell, 2022/01/20
- [PULL 08/38] tests/acpi/bios-tables-test: Allow changes to virt/PPTT file, Peter Maydell, 2022/01/20
- [PULL 02/38] hw: Move MARVELL_88W8618 Kconfig from audio/ to arm/, Peter Maydell, 2022/01/20
- [PULL 12/38] virtio-mem: Correct default THP size for ARM64, Peter Maydell, 2022/01/20
- [PULL 14/38] hw/intc/arm_gic: Implement read of GICC_IIDR, Peter Maydell, 2022/01/20
- [PULL 23/38] hw/misc/aspeed_i3c.c: Introduce a dummy AST2600 I3C model., Peter Maydell, 2022/01/20
- [PULL 35/38] hw/intc/arm_gicv3_its: Factor out "find address of table entry" code,
Peter Maydell <=
- [PULL 18/38] hw/arm/virt: Honor highmem setting when computing the memory map, Peter Maydell, 2022/01/20
- [PULL 34/38] hw/intc/arm_gicv3_its: Fix return codes in process_mapd(), Peter Maydell, 2022/01/20
- [PULL 31/38] hw/intc/arm_gicv3_its: Refactor process_its_cmd() to reduce nesting, Peter Maydell, 2022/01/20
- [PULL 20/38] hw/arm/virt: Disable highmem devices that don't fit in the PA range, Peter Maydell, 2022/01/20
- [PULL 22/38] hw/arm: kudo add lm75s behind bus 1 switch at 75, Peter Maydell, 2022/01/20
- [PULL 29/38] hw/intc/arm_gicv3_its: Use enum for return value of process_* functions, Peter Maydell, 2022/01/20
- [PULL 07/38] hw/acpi/aml-build: Improve scalability of PPTT generation, Peter Maydell, 2022/01/20
- [PULL 06/38] hw/arm/virt: Support cluster level in DT cpu-map, Peter Maydell, 2022/01/20
- [PULL 04/38] hw/net: Move MV88W8618 network device out of hw/arm/ directory, Peter Maydell, 2022/01/20
- [PULL 03/38] hw/arm/musicpal: Fix coding style of code related to MV88W8618 device, Peter Maydell, 2022/01/20