* [RFC v4 01/31] hw/arm/smmuv3-common: Fix incorrect reserved mask for SMMU CR0 register
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
@ 2026-02-21 10:02 ` Tao Tang
2026-02-25 20:18 ` Pierrick Bouvier
2026-02-27 14:31 ` Mostafa Saleh
2026-02-21 10:02 ` [RFC v4 02/31] hw/arm/smmuv3: Correct SMMUEN field name in CR0 Tao Tang
` (29 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:02 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
The current definition of the SMMU_CR0_RESERVED mask is incorrect.
It mistakenly treats bit 10 (DPT_WALK_EN) as a reserved bit while
treating bit 9 (RES0) as an implemented bit.
According to the SMMU architecture specification, the layout for CR0 is:
| 31:11| RES0 |
| 10 | DPT_WALK_EN |
| 9 | RES0 |
| 8:6 | VMW |
| 5 | RES0 |
| 4 | ATSCHK |
| 3 | CMDQEN |
| 2 | EVENTQEN |
| 1 | PRIQEN |
| 0 | SMMUEN |
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Link: https://lists.gnu.org/archive/html/qemu-arm/2025-06/msg00088.html
---
include/hw/arm/smmuv3-common.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/include/hw/arm/smmuv3-common.h b/include/hw/arm/smmuv3-common.h
index 67a23fbeaae..2df54ba60f9 100644
--- a/include/hw/arm/smmuv3-common.h
+++ b/include/hw/arm/smmuv3-common.h
@@ -355,7 +355,7 @@ REG32(CR0, 0x20)
FIELD(CR0, EVENTQEN, 2, 1)
FIELD(CR0, CMDQEN, 3, 1)
-#define SMMU_CR0_RESERVED 0xFFFFFC20
+#define SMMU_CR0_RESERVED 0xFFFFFA20
REG32(CR0ACK, 0x24)
REG32(CR1, 0x28)
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 01/31] hw/arm/smmuv3-common: Fix incorrect reserved mask for SMMU CR0 register
2026-02-21 10:02 ` [RFC v4 01/31] hw/arm/smmuv3-common: Fix incorrect reserved mask for SMMU CR0 register Tao Tang
@ 2026-02-25 20:18 ` Pierrick Bouvier
2026-02-27 14:31 ` Mostafa Saleh
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 20:18 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:02 AM, Tao Tang wrote:
> The current definition of the SMMU_CR0_RESERVED mask is incorrect.
> It mistakenly treats bit 10 (DPT_WALK_EN) as a reserved bit while
> treating bit 9 (RES0) as an implemented bit.
>
> According to the SMMU architecture specification, the layout for CR0 is:
> | 31:11| RES0 |
> | 10 | DPT_WALK_EN |
> | 9 | RES0 |
> | 8:6 | VMW |
> | 5 | RES0 |
> | 4 | ATSCHK |
> | 3 | CMDQEN |
> | 2 | EVENTQEN |
> | 1 | PRIQEN |
> | 0 | SMMUEN |
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Link: https://lists.gnu.org/archive/html/qemu-arm/2025-06/msg00088.html
> ---
> include/hw/arm/smmuv3-common.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 01/31] hw/arm/smmuv3-common: Fix incorrect reserved mask for SMMU CR0 register
2026-02-21 10:02 ` [RFC v4 01/31] hw/arm/smmuv3-common: Fix incorrect reserved mask for SMMU CR0 register Tao Tang
2026-02-25 20:18 ` Pierrick Bouvier
@ 2026-02-27 14:31 ` Mostafa Saleh
1 sibling, 0 replies; 136+ messages in thread
From: Mostafa Saleh @ 2026-02-27 14:31 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sat, Feb 21, 2026 at 06:02:20PM +0800, Tao Tang wrote:
> The current definition of the SMMU_CR0_RESERVED mask is incorrect.
> It mistakenly treats bit 10 (DPT_WALK_EN) as a reserved bit while
> treating bit 9 (RES0) as an implemented bit.
>
> According to the SMMU architecture specification, the layout for CR0 is:
> | 31:11| RES0 |
> | 10 | DPT_WALK_EN |
> | 9 | RES0 |
> | 8:6 | VMW |
> | 5 | RES0 |
> | 4 | ATSCHK |
> | 3 | CMDQEN |
> | 2 | EVENTQEN |
> | 1 | PRIQEN |
> | 0 | SMMUEN |
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Link: https://lists.gnu.org/archive/html/qemu-arm/2025-06/msg00088.html
I think fixes as this, should be separate, that would make the series
smaller.
Reviewed-by: Mostafa Saleh <smostafa@google.com>
Thanks,
Mostafa
> ---
> include/hw/arm/smmuv3-common.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/include/hw/arm/smmuv3-common.h b/include/hw/arm/smmuv3-common.h
> index 67a23fbeaae..2df54ba60f9 100644
> --- a/include/hw/arm/smmuv3-common.h
> +++ b/include/hw/arm/smmuv3-common.h
> @@ -355,7 +355,7 @@ REG32(CR0, 0x20)
> FIELD(CR0, EVENTQEN, 2, 1)
> FIELD(CR0, CMDQEN, 3, 1)
>
> -#define SMMU_CR0_RESERVED 0xFFFFFC20
> +#define SMMU_CR0_RESERVED 0xFFFFFA20
>
> REG32(CR0ACK, 0x24)
> REG32(CR1, 0x28)
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 02/31] hw/arm/smmuv3: Correct SMMUEN field name in CR0
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
2026-02-21 10:02 ` [RFC v4 01/31] hw/arm/smmuv3-common: Fix incorrect reserved mask for SMMU CR0 register Tao Tang
@ 2026-02-21 10:02 ` Tao Tang
2026-02-25 20:18 ` Pierrick Bouvier
2026-02-27 14:31 ` Mostafa Saleh
2026-02-21 10:02 ` [RFC v4 03/31] hw/arm/smmuv3: Introduce secure registers Tao Tang
` (28 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:02 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
The FIELD macro for the SMMU enable bit in the CR0 register was
incorrectly named SMMU_ENABLE.
The ARM SMMUv3 Architecture Specification (both older IHI 0070.E.a and
newer IHI 0070.G.b) consistently refers to the SMMU enable bit as SMMUEN.
This change makes our implementation consistent with the manual.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Link: https://lists.nongnu.org/archive/html/qemu-arm/2025-09/msg01270.html
---
hw/arm/smmuv3-internal.h | 2 +-
include/hw/arm/smmuv3-common.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index a6464425ec3..ebdb4ebae67 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -41,7 +41,7 @@ typedef enum SMMUTranslationClass {
static inline int smmu_enabled(SMMUv3State *s)
{
- return FIELD_EX32(s->cr[0], CR0, SMMU_ENABLE);
+ return FIELD_EX32(s->cr[0], CR0, SMMUEN);
}
/* Command Queue Entry */
diff --git a/include/hw/arm/smmuv3-common.h b/include/hw/arm/smmuv3-common.h
index 2df54ba60f9..9f78bbe89eb 100644
--- a/include/hw/arm/smmuv3-common.h
+++ b/include/hw/arm/smmuv3-common.h
@@ -351,7 +351,7 @@ REG32(IDR5, 0x14)
REG32(IIDR, 0x18)
REG32(AIDR, 0x1c)
REG32(CR0, 0x20)
- FIELD(CR0, SMMU_ENABLE, 0, 1)
+ FIELD(CR0, SMMUEN, 0, 1)
FIELD(CR0, EVENTQEN, 2, 1)
FIELD(CR0, CMDQEN, 3, 1)
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 02/31] hw/arm/smmuv3: Correct SMMUEN field name in CR0
2026-02-21 10:02 ` [RFC v4 02/31] hw/arm/smmuv3: Correct SMMUEN field name in CR0 Tao Tang
@ 2026-02-25 20:18 ` Pierrick Bouvier
2026-02-27 14:31 ` Mostafa Saleh
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 20:18 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:02 AM, Tao Tang wrote:
> The FIELD macro for the SMMU enable bit in the CR0 register was
> incorrectly named SMMU_ENABLE.
>
> The ARM SMMUv3 Architecture Specification (both older IHI 0070.E.a and
> newer IHI 0070.G.b) consistently refers to the SMMU enable bit as SMMUEN.
>
> This change makes our implementation consistent with the manual.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Link: https://lists.nongnu.org/archive/html/qemu-arm/2025-09/msg01270.html
> ---
> hw/arm/smmuv3-internal.h | 2 +-
> include/hw/arm/smmuv3-common.h | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 02/31] hw/arm/smmuv3: Correct SMMUEN field name in CR0
2026-02-21 10:02 ` [RFC v4 02/31] hw/arm/smmuv3: Correct SMMUEN field name in CR0 Tao Tang
2026-02-25 20:18 ` Pierrick Bouvier
@ 2026-02-27 14:31 ` Mostafa Saleh
1 sibling, 0 replies; 136+ messages in thread
From: Mostafa Saleh @ 2026-02-27 14:31 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sat, Feb 21, 2026 at 06:02:21PM +0800, Tao Tang wrote:
> The FIELD macro for the SMMU enable bit in the CR0 register was
> incorrectly named SMMU_ENABLE.
>
> The ARM SMMUv3 Architecture Specification (both older IHI 0070.E.a and
> newer IHI 0070.G.b) consistently refers to the SMMU enable bit as SMMUEN.
>
> This change makes our implementation consistent with the manual.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Link: https://lists.nongnu.org/archive/html/qemu-arm/2025-09/msg01270.html
Same comment about fixes.
Reviewed-by: Mostafa Saleh <smostafa@google.com>
Thanks,
Mostafa
> ---
> hw/arm/smmuv3-internal.h | 2 +-
> include/hw/arm/smmuv3-common.h | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> index a6464425ec3..ebdb4ebae67 100644
> --- a/hw/arm/smmuv3-internal.h
> +++ b/hw/arm/smmuv3-internal.h
> @@ -41,7 +41,7 @@ typedef enum SMMUTranslationClass {
>
> static inline int smmu_enabled(SMMUv3State *s)
> {
> - return FIELD_EX32(s->cr[0], CR0, SMMU_ENABLE);
> + return FIELD_EX32(s->cr[0], CR0, SMMUEN);
> }
>
> /* Command Queue Entry */
> diff --git a/include/hw/arm/smmuv3-common.h b/include/hw/arm/smmuv3-common.h
> index 2df54ba60f9..9f78bbe89eb 100644
> --- a/include/hw/arm/smmuv3-common.h
> +++ b/include/hw/arm/smmuv3-common.h
> @@ -351,7 +351,7 @@ REG32(IDR5, 0x14)
> REG32(IIDR, 0x18)
> REG32(AIDR, 0x1c)
> REG32(CR0, 0x20)
> - FIELD(CR0, SMMU_ENABLE, 0, 1)
> + FIELD(CR0, SMMUEN, 0, 1)
> FIELD(CR0, EVENTQEN, 2, 1)
> FIELD(CR0, CMDQEN, 3, 1)
>
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 03/31] hw/arm/smmuv3: Introduce secure registers
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
2026-02-21 10:02 ` [RFC v4 01/31] hw/arm/smmuv3-common: Fix incorrect reserved mask for SMMU CR0 register Tao Tang
2026-02-21 10:02 ` [RFC v4 02/31] hw/arm/smmuv3: Correct SMMUEN field name in CR0 Tao Tang
@ 2026-02-21 10:02 ` Tao Tang
2026-02-25 20:23 ` Pierrick Bouvier
2026-02-27 14:33 ` Mostafa Saleh
2026-02-21 10:02 ` [RFC v4 04/31] hw/arm/smmuv3: Introduce banked registers for SMMUv3 state Tao Tang
` (27 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:02 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
The Arm SMMUv3 architecture defines a set of registers for managing
secure transactions and context.
This patch introduces the definitions for these secure registers within
the SMMUv3 device model internal header.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Link: https://lore.kernel.org/qemu-devel/759ec110-365f-488b-802d-c7bb1efe30bc@redhat.com/
---
include/hw/arm/smmuv3-common.h | 70 +++++++++++++++++++++++++++++++++-
1 file changed, 69 insertions(+), 1 deletion(-)
diff --git a/include/hw/arm/smmuv3-common.h b/include/hw/arm/smmuv3-common.h
index 9f78bbe89eb..c40fa46fb88 100644
--- a/include/hw/arm/smmuv3-common.h
+++ b/include/hw/arm/smmuv3-common.h
@@ -269,7 +269,7 @@ REG32(CD_5, 20)
((sel) ? ((cd)->word[4] = FIELD_DP32((cd)->word[4], CD_4, NSCFG1, (v))) : \
((cd)->word[2] = FIELD_DP32((cd)->word[2], CD_2, NSCFG0, (v))))
-/* MMIO Registers */
+/* MMIO Registers. Shared by Non-secure/Realm/Root states. */
REG32(IDR0, 0x0)
FIELD(IDR0, S2P, 0 , 1)
@@ -356,6 +356,7 @@ REG32(CR0, 0x20)
FIELD(CR0, CMDQEN, 3, 1)
#define SMMU_CR0_RESERVED 0xFFFFFA20
+#define SMMU_S_CR0_RESERVED 0xFFFFFC12
REG32(CR0ACK, 0x24)
REG32(CR1, 0x28)
@@ -414,6 +415,73 @@ REG32(EVENTQ_IRQ_CFG2, 0xbc)
#define A_IDREGS 0xfd0
+#define SMMU_SECURE_REG_START 0x8000 /* Start of secure-only registers */
+
+REG32(S_IDR0, 0x8000)
+ FIELD(S_IDR0, STALL_MODEL, 24, 2)
+REG32(S_IDR1, 0x8004)
+ FIELD(S_IDR1, S_SIDSIZE, 0 , 6)
+ FIELD(S_IDR1, SEL2, 29, 1)
+ FIELD(S_IDR1, SECURE_IMPL, 31, 1)
+
+REG32(S_IDR2, 0x8008)
+REG32(S_IDR3, 0x800c)
+REG32(S_IDR4, 0x8010)
+
+REG32(S_CR0, 0x8020)
+ FIELD(S_CR0, SMMUEN, 0, 1)
+ FIELD(S_CR0, EVENTQEN, 2, 1)
+ FIELD(S_CR0, CMDQEN, 3, 1)
+
+REG32(S_CR0ACK, 0x8024)
+REG32(S_CR1, 0x8028)
+REG32(S_CR2, 0x802c)
+
+REG32(S_INIT, 0x803c)
+ FIELD(S_INIT, INV_ALL, 0, 1)
+
+REG32(S_GBPA, 0x8044)
+ FIELD(S_GBPA, ABORT, 20, 1)
+ FIELD(S_GBPA, UPDATE, 31, 1)
+
+REG32(S_IRQ_CTRL, 0x8050)
+ FIELD(S_IRQ_CTRL, GERROR_IRQEN, 0, 1)
+ FIELD(S_IRQ_CTRL, EVENTQ_IRQEN, 2, 1)
+
+REG32(S_IRQ_CTRLACK, 0x8054)
+
+REG32(S_GERROR, 0x8060)
+ FIELD(S_GERROR, CMDQ_ERR, 0, 1)
+
+#define SMMU_GERROR_IRQ_CFG0_RESERVED 0x00FFFFFFFFFFFFFC
+#define SMMU_GERROR_IRQ_CFG2_RESERVED 0x000000000000003F
+
+#define SMMU_STRTAB_BASE_RESERVED 0x40FFFFFFFFFFFFC0
+#define SMMU_QUEUE_BASE_RESERVED 0x40FFFFFFFFFFFFFF
+#define SMMU_EVENTQ_IRQ_CFG0_RESERVED 0x00FFFFFFFFFFFFFC
+
+REG32(S_GERRORN, 0x8064)
+REG64(S_GERROR_IRQ_CFG0, 0x8068)
+REG32(S_GERROR_IRQ_CFG1, 0x8070)
+REG32(S_GERROR_IRQ_CFG2, 0x8074)
+REG64(S_STRTAB_BASE, 0x8080)
+REG32(S_STRTAB_BASE_CFG, 0x8088)
+ FIELD(S_STRTAB_BASE_CFG, LOG2SIZE, 0, 6)
+ FIELD(S_STRTAB_BASE_CFG, SPLIT, 6, 5)
+ FIELD(S_STRTAB_BASE_CFG, FMT, 16, 2)
+
+REG64(S_CMDQ_BASE, 0x8090)
+REG32(S_CMDQ_PROD, 0x8098)
+REG32(S_CMDQ_CONS, 0x809c)
+ FIELD(S_CMDQ_CONS, ERR, 24, 7)
+
+REG64(S_EVENTQ_BASE, 0x80a0)
+REG32(S_EVENTQ_PROD, 0x80a8)
+REG32(S_EVENTQ_CONS, 0x80ac)
+REG64(S_EVENTQ_IRQ_CFG0, 0x80b0)
+REG32(S_EVENTQ_IRQ_CFG1, 0x80b8)
+REG32(S_EVENTQ_IRQ_CFG2, 0x80bc)
+
/* Commands */
typedef enum SMMUCommandType {
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 03/31] hw/arm/smmuv3: Introduce secure registers
2026-02-21 10:02 ` [RFC v4 03/31] hw/arm/smmuv3: Introduce secure registers Tao Tang
@ 2026-02-25 20:23 ` Pierrick Bouvier
2026-02-27 14:33 ` Mostafa Saleh
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 20:23 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:02 AM, Tao Tang wrote:
> The Arm SMMUv3 architecture defines a set of registers for managing
> secure transactions and context.
>
> This patch introduces the definitions for these secure registers within
> the SMMUv3 device model internal header.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Link: https://lore.kernel.org/qemu-devel/759ec110-365f-488b-802d-c7bb1efe30bc@redhat.com/
> ---
> include/hw/arm/smmuv3-common.h | 70 +++++++++++++++++++++++++++++++++-
> 1 file changed, 69 insertions(+), 1 deletion(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 03/31] hw/arm/smmuv3: Introduce secure registers
2026-02-21 10:02 ` [RFC v4 03/31] hw/arm/smmuv3: Introduce secure registers Tao Tang
2026-02-25 20:23 ` Pierrick Bouvier
@ 2026-02-27 14:33 ` Mostafa Saleh
1 sibling, 0 replies; 136+ messages in thread
From: Mostafa Saleh @ 2026-02-27 14:33 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sat, Feb 21, 2026 at 06:02:22PM +0800, Tao Tang wrote:
> The Arm SMMUv3 architecture defines a set of registers for managing
> secure transactions and context.
>
> This patch introduces the definitions for these secure registers within
> the SMMUv3 device model internal header.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Link: https://lore.kernel.org/qemu-devel/759ec110-365f-488b-802d-c7bb1efe30bc@redhat.com/
Reviewed-by: Mostafa Saleh <smostafa@google.com>
Thanks,
Mostafa
> ---
> include/hw/arm/smmuv3-common.h | 70 +++++++++++++++++++++++++++++++++-
> 1 file changed, 69 insertions(+), 1 deletion(-)
>
> diff --git a/include/hw/arm/smmuv3-common.h b/include/hw/arm/smmuv3-common.h
> index 9f78bbe89eb..c40fa46fb88 100644
> --- a/include/hw/arm/smmuv3-common.h
> +++ b/include/hw/arm/smmuv3-common.h
> @@ -269,7 +269,7 @@ REG32(CD_5, 20)
> ((sel) ? ((cd)->word[4] = FIELD_DP32((cd)->word[4], CD_4, NSCFG1, (v))) : \
> ((cd)->word[2] = FIELD_DP32((cd)->word[2], CD_2, NSCFG0, (v))))
>
> -/* MMIO Registers */
> +/* MMIO Registers. Shared by Non-secure/Realm/Root states. */
>
> REG32(IDR0, 0x0)
> FIELD(IDR0, S2P, 0 , 1)
> @@ -356,6 +356,7 @@ REG32(CR0, 0x20)
> FIELD(CR0, CMDQEN, 3, 1)
>
> #define SMMU_CR0_RESERVED 0xFFFFFA20
> +#define SMMU_S_CR0_RESERVED 0xFFFFFC12
>
> REG32(CR0ACK, 0x24)
> REG32(CR1, 0x28)
> @@ -414,6 +415,73 @@ REG32(EVENTQ_IRQ_CFG2, 0xbc)
>
> #define A_IDREGS 0xfd0
>
> +#define SMMU_SECURE_REG_START 0x8000 /* Start of secure-only registers */
> +
> +REG32(S_IDR0, 0x8000)
> + FIELD(S_IDR0, STALL_MODEL, 24, 2)
> +REG32(S_IDR1, 0x8004)
> + FIELD(S_IDR1, S_SIDSIZE, 0 , 6)
> + FIELD(S_IDR1, SEL2, 29, 1)
> + FIELD(S_IDR1, SECURE_IMPL, 31, 1)
> +
> +REG32(S_IDR2, 0x8008)
> +REG32(S_IDR3, 0x800c)
> +REG32(S_IDR4, 0x8010)
> +
> +REG32(S_CR0, 0x8020)
> + FIELD(S_CR0, SMMUEN, 0, 1)
> + FIELD(S_CR0, EVENTQEN, 2, 1)
> + FIELD(S_CR0, CMDQEN, 3, 1)
> +
> +REG32(S_CR0ACK, 0x8024)
> +REG32(S_CR1, 0x8028)
> +REG32(S_CR2, 0x802c)
> +
> +REG32(S_INIT, 0x803c)
> + FIELD(S_INIT, INV_ALL, 0, 1)
> +
> +REG32(S_GBPA, 0x8044)
> + FIELD(S_GBPA, ABORT, 20, 1)
> + FIELD(S_GBPA, UPDATE, 31, 1)
> +
> +REG32(S_IRQ_CTRL, 0x8050)
> + FIELD(S_IRQ_CTRL, GERROR_IRQEN, 0, 1)
> + FIELD(S_IRQ_CTRL, EVENTQ_IRQEN, 2, 1)
> +
> +REG32(S_IRQ_CTRLACK, 0x8054)
> +
> +REG32(S_GERROR, 0x8060)
> + FIELD(S_GERROR, CMDQ_ERR, 0, 1)
> +
> +#define SMMU_GERROR_IRQ_CFG0_RESERVED 0x00FFFFFFFFFFFFFC
> +#define SMMU_GERROR_IRQ_CFG2_RESERVED 0x000000000000003F
> +
> +#define SMMU_STRTAB_BASE_RESERVED 0x40FFFFFFFFFFFFC0
> +#define SMMU_QUEUE_BASE_RESERVED 0x40FFFFFFFFFFFFFF
> +#define SMMU_EVENTQ_IRQ_CFG0_RESERVED 0x00FFFFFFFFFFFFFC
> +
> +REG32(S_GERRORN, 0x8064)
> +REG64(S_GERROR_IRQ_CFG0, 0x8068)
> +REG32(S_GERROR_IRQ_CFG1, 0x8070)
> +REG32(S_GERROR_IRQ_CFG2, 0x8074)
> +REG64(S_STRTAB_BASE, 0x8080)
> +REG32(S_STRTAB_BASE_CFG, 0x8088)
> + FIELD(S_STRTAB_BASE_CFG, LOG2SIZE, 0, 6)
> + FIELD(S_STRTAB_BASE_CFG, SPLIT, 6, 5)
> + FIELD(S_STRTAB_BASE_CFG, FMT, 16, 2)
> +
> +REG64(S_CMDQ_BASE, 0x8090)
> +REG32(S_CMDQ_PROD, 0x8098)
> +REG32(S_CMDQ_CONS, 0x809c)
> + FIELD(S_CMDQ_CONS, ERR, 24, 7)
> +
> +REG64(S_EVENTQ_BASE, 0x80a0)
> +REG32(S_EVENTQ_PROD, 0x80a8)
> +REG32(S_EVENTQ_CONS, 0x80ac)
> +REG64(S_EVENTQ_IRQ_CFG0, 0x80b0)
> +REG32(S_EVENTQ_IRQ_CFG1, 0x80b8)
> +REG32(S_EVENTQ_IRQ_CFG2, 0x80bc)
> +
> /* Commands */
>
> typedef enum SMMUCommandType {
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 04/31] hw/arm/smmuv3: Introduce banked registers for SMMUv3 state
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (2 preceding siblings ...)
2026-02-21 10:02 ` [RFC v4 03/31] hw/arm/smmuv3: Introduce secure registers Tao Tang
@ 2026-02-21 10:02 ` Tao Tang
2026-02-25 20:26 ` Pierrick Bouvier
2026-02-27 14:38 ` Mostafa Saleh
2026-02-21 10:02 ` [RFC v4 05/31] hw/arm/smmuv3: Thread SEC_SID through helper APIs Tao Tang
` (26 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:02 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Rework the SMMUv3 state management by introducing a banked register
structure. This is a purely mechanical refactoring with no functional
changes.
To support multiple security states, a new enum, SMMUSecSID, is
introduced to identify each state, sticking to the spec terminology.
A new structure, SMMUv3RegBank, is then defined to hold the state
for a single security context. The main SMMUv3State now contains an
array of these banks, indexed by SMMUSecSID. This avoids the need for
separate fields for non-secure and future secure registers.
All existing code, which handles only the Non-secure state, is updated
to access its state via s->bank[SMMU_SEC_SID_NS]. A local bank helper
pointer is used where it improves readability.
Function signatures and logic remain untouched in this commit to
isolate the structural changes and simplify review. This is the
foundational step for building multi-security-state support.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
hw/arm/smmuv3-accel.c | 42 +++--
hw/arm/smmuv3-internal.h | 24 ++-
hw/arm/smmuv3.c | 345 +++++++++++++++++++----------------
include/hw/arm/smmu-common.h | 6 +
include/hw/arm/smmuv3.h | 30 ++-
5 files changed, 257 insertions(+), 190 deletions(-)
diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
index f5cd4df336a..30d4b38c0a3 100644
--- a/hw/arm/smmuv3-accel.c
+++ b/hw/arm/smmuv3-accel.c
@@ -40,19 +40,20 @@ smmuv3_accel_check_hw_compatible(SMMUv3State *s,
struct iommu_hw_info_arm_smmuv3 *info,
Error **errp)
{
+ SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
/* QEMU SMMUv3 supports both linear and 2-level stream tables */
if (FIELD_EX32(info->idr[0], IDR0, STLEVEL) !=
- FIELD_EX32(s->idr[0], IDR0, STLEVEL)) {
+ FIELD_EX32(bank->idr[0], IDR0, STLEVEL)) {
error_setg(errp, "Host SMMUv3 Stream Table format mismatch "
"(host STLEVEL=%u, QEMU STLEVEL=%u)",
FIELD_EX32(info->idr[0], IDR0, STLEVEL),
- FIELD_EX32(s->idr[0], IDR0, STLEVEL));
+ FIELD_EX32(bank->idr[0], IDR0, STLEVEL));
return false;
}
/* QEMU SMMUv3 supports only little-endian translation table walks */
if (FIELD_EX32(info->idr[0], IDR0, TTENDIAN) >
- FIELD_EX32(s->idr[0], IDR0, TTENDIAN)) {
+ FIELD_EX32(bank->idr[0], IDR0, TTENDIAN)) {
error_setg(errp, "Host SMMUv3 doesn't support Little-endian "
"translation table");
return false;
@@ -60,7 +61,7 @@ smmuv3_accel_check_hw_compatible(SMMUv3State *s,
/* QEMU SMMUv3 supports only AArch64 translation table format */
if (FIELD_EX32(info->idr[0], IDR0, TTF) <
- FIELD_EX32(s->idr[0], IDR0, TTF)) {
+ FIELD_EX32(bank->idr[0], IDR0, TTF)) {
error_setg(errp, "Host SMMUv3 doesn't support AArch64 translation "
"table format");
return false;
@@ -68,53 +69,53 @@ smmuv3_accel_check_hw_compatible(SMMUv3State *s,
/* QEMU SMMUv3 supports SIDSIZE 16 */
if (FIELD_EX32(info->idr[1], IDR1, SIDSIZE) <
- FIELD_EX32(s->idr[1], IDR1, SIDSIZE)) {
+ FIELD_EX32(bank->idr[1], IDR1, SIDSIZE)) {
error_setg(errp, "Host SMMUv3 SIDSIZE not compatible "
"(host=%u, QEMU=%u)",
FIELD_EX32(info->idr[1], IDR1, SIDSIZE),
- FIELD_EX32(s->idr[1], IDR1, SIDSIZE));
+ FIELD_EX32(bank->idr[1], IDR1, SIDSIZE));
return false;
}
/* Check SSIDSIZE value opted-in is compatible with Host SMMUv3 SSIDSIZE */
if (FIELD_EX32(info->idr[1], IDR1, SSIDSIZE) <
- FIELD_EX32(s->idr[1], IDR1, SSIDSIZE)) {
+ FIELD_EX32(bank->idr[1], IDR1, SSIDSIZE)) {
error_setg(errp, "Host SMMUv3 SSIDSIZE not compatible "
"(host=%u, QEMU=%u)",
FIELD_EX32(info->idr[1], IDR1, SSIDSIZE),
- FIELD_EX32(s->idr[1], IDR1, SSIDSIZE));
+ FIELD_EX32(bank->idr[1], IDR1, SSIDSIZE));
return false;
}
/* User can disable QEMU SMMUv3 Range Invalidation support */
if (FIELD_EX32(info->idr[3], IDR3, RIL) <
- FIELD_EX32(s->idr[3], IDR3, RIL)) {
+ FIELD_EX32(bank->idr[3], IDR3, RIL)) {
error_setg(errp, "Host SMMUv3 doesn't support Range Invalidation");
return false;
}
/* Check OAS value opted is compatible with Host SMMUv3 IPA */
if (FIELD_EX32(info->idr[5], IDR5, OAS) <
- FIELD_EX32(s->idr[5], IDR5, OAS)) {
+ FIELD_EX32(bank->idr[5], IDR5, OAS)) {
error_setg(errp, "Host SMMUv3 supports only %d-bit IPA, but the vSMMU "
"OAS implies %d-bit IPA",
smmuv3_oas_bits(FIELD_EX32(info->idr[5], IDR5, OAS)),
- smmuv3_oas_bits(FIELD_EX32(s->idr[5], IDR5, OAS)));
+ smmuv3_oas_bits(FIELD_EX32(bank->idr[5], IDR5, OAS)));
return false;
}
/* QEMU SMMUv3 supports GRAN4K/GRAN16K/GRAN64K translation granules */
if (FIELD_EX32(info->idr[5], IDR5, GRAN4K) !=
- FIELD_EX32(s->idr[5], IDR5, GRAN4K)) {
+ FIELD_EX32(bank->idr[5], IDR5, GRAN4K)) {
error_setg(errp, "Host SMMUv3 doesn't support 4K translation granule");
return false;
}
if (FIELD_EX32(info->idr[5], IDR5, GRAN16K) !=
- FIELD_EX32(s->idr[5], IDR5, GRAN16K)) {
+ FIELD_EX32(bank->idr[5], IDR5, GRAN16K)) {
error_setg(errp, "Host SMMUv3 doesn't support 16K translation granule");
return false;
}
if (FIELD_EX32(info->idr[5], IDR5, GRAN64K) !=
- FIELD_EX32(s->idr[5], IDR5, GRAN64K)) {
+ FIELD_EX32(bank->idr[5], IDR5, GRAN64K)) {
error_setg(errp, "Host SMMUv3 doesn't support 64K translation granule");
return false;
}
@@ -168,7 +169,8 @@ static SMMUv3AccelDevice *smmuv3_accel_get_dev(SMMUState *bs, SMMUPciBus *sbus,
static uint32_t smmuv3_accel_gbpa_hwpt(SMMUv3State *s, SMMUv3AccelState *accel)
{
- return FIELD_EX32(s->gbpa, GBPA, ABORT) ?
+ SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
+ return FIELD_EX32(bank->gbpa, GBPA, ABORT) ?
accel->abort_hwpt_id : accel->bypass_hwpt_id;
}
@@ -687,22 +689,24 @@ void smmuv3_accel_idr_override(SMMUv3State *s)
return;
}
+ SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
+
/* By default QEMU SMMUv3 has RIL. Update IDR3 if user has disabled it */
- s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, s->ril);
+ bank->idr[3] = FIELD_DP32(bank->idr[3], IDR3, RIL, s->ril);
/* QEMU SMMUv3 has no ATS. Advertise ATS if opt-in by property */
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, ATS, s->ats);
+ bank->idr[0] = FIELD_DP32(bank->idr[0], IDR0, ATS, s->ats);
/* Advertise 48-bit OAS in IDR5 when requested (default is 44 bits). */
if (s->oas == SMMU_OAS_48BIT) {
- s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS_48);
+ bank->idr[5] = FIELD_DP32(bank->idr[5], IDR5, OAS, SMMU_IDR5_OAS_48);
}
/*
* By default QEMU SMMUv3 has no SubstreamID support. Update IDR1 if user
* has enabled it.
*/
- s->idr[1] = FIELD_DP32(s->idr[1], IDR1, SSIDSIZE, s->ssidsize);
+ bank->idr[1] = FIELD_DP32(bank->idr[1], IDR1, SSIDSIZE, s->ssidsize);
}
/* Based on SMUUv3 GPBA.ABORT configuration, attach a corresponding HWPT */
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index ebdb4ebae67..deb1ef60e87 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -41,7 +41,9 @@ typedef enum SMMUTranslationClass {
static inline int smmu_enabled(SMMUv3State *s)
{
- return FIELD_EX32(s->cr[0], CR0, SMMUEN);
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
+ return FIELD_EX32(bank->cr[0], CR0, SMMUEN);
}
/* Command Queue Entry */
@@ -69,12 +71,16 @@ static inline uint32_t smmuv3_idreg(int regoffset)
static inline bool smmuv3_eventq_irq_enabled(SMMUv3State *s)
{
- return FIELD_EX32(s->irq_ctrl, IRQ_CTRL, EVENTQ_IRQEN);
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
+ return FIELD_EX32(bank->irq_ctrl, IRQ_CTRL, EVENTQ_IRQEN);
}
static inline bool smmuv3_gerror_irq_enabled(SMMUv3State *s)
{
- return FIELD_EX32(s->irq_ctrl, IRQ_CTRL, GERROR_IRQEN);
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
+ return FIELD_EX32(bank->irq_ctrl, IRQ_CTRL, GERROR_IRQEN);
}
/* Queue Handling */
@@ -119,17 +125,23 @@ static inline void queue_cons_incr(SMMUQueue *q)
static inline bool smmuv3_cmdq_enabled(SMMUv3State *s)
{
- return FIELD_EX32(s->cr[0], CR0, CMDQEN);
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
+ return FIELD_EX32(bank->cr[0], CR0, CMDQEN);
}
static inline bool smmuv3_eventq_enabled(SMMUv3State *s)
{
- return FIELD_EX32(s->cr[0], CR0, EVENTQEN);
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
+ return FIELD_EX32(bank->cr[0], CR0, EVENTQEN);
}
static inline void smmu_write_cmdq_err(SMMUv3State *s, uint32_t err_type)
{
- s->cmdq.cons = FIELD_DP32(s->cmdq.cons, CMDQ_CONS, ERR, err_type);
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
+ bank->cmdq.cons = FIELD_DP32(bank->cmdq.cons, CMDQ_CONS, ERR, err_type);
}
static const char *cmd_stringify[] = {
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index c08d58c5790..5511585601d 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -52,6 +52,8 @@
static void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq,
uint32_t gerror_mask)
{
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
bool pulse = false;
@@ -67,15 +69,15 @@ static void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq,
break;
case SMMU_IRQ_GERROR:
{
- uint32_t pending = s->gerror ^ s->gerrorn;
+ uint32_t pending = bank->gerror ^ bank->gerrorn;
uint32_t new_gerrors = ~pending & gerror_mask;
if (!new_gerrors) {
/* only toggle non pending errors */
return;
}
- s->gerror ^= new_gerrors;
- trace_smmuv3_write_gerror(new_gerrors, s->gerror);
+ bank->gerror ^= new_gerrors;
+ trace_smmuv3_write_gerror(new_gerrors, bank->gerror);
pulse = smmuv3_gerror_irq_enabled(s);
break;
@@ -89,8 +91,10 @@ static void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq,
static void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_gerrorn)
{
- uint32_t pending = s->gerror ^ s->gerrorn;
- uint32_t toggled = s->gerrorn ^ new_gerrorn;
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
+ uint32_t pending = bank->gerror ^ bank->gerrorn;
+ uint32_t toggled = bank->gerrorn ^ new_gerrorn;
if (toggled & ~pending) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -102,9 +106,9 @@ static void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_gerrorn)
* We do not raise any error in case guest toggles bits corresponding
* to not active IRQs (CONSTRAINED UNPREDICTABLE)
*/
- s->gerrorn = new_gerrorn;
+ bank->gerrorn = new_gerrorn;
- trace_smmuv3_write_gerrorn(toggled & pending, s->gerrorn);
+ trace_smmuv3_write_gerrorn(toggled & pending, bank->gerrorn);
}
static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd)
@@ -146,7 +150,9 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
{
- SMMUQueue *q = &s->eventq;
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
+ SMMUQueue *q = &bank->eventq;
MemTxResult r;
if (!smmuv3_eventq_enabled(s)) {
@@ -266,69 +272,75 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
*/
static void smmuv3_init_id_regs(SMMUv3State *s)
{
+ SMMUv3RegBank *bk = smmuv3_bank(s, SMMU_SEC_SID_NS);
+
/* Based on sys property, the stages supported in smmu will be advertised.*/
if (s->stage && !strcmp("2", s->stage)) {
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S2P, 1);
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, S2P, 1);
} else if (s->stage && !strcmp("nested", s->stage)) {
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S1P, 1);
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S2P, 1);
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, S1P, 1);
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, S2P, 1);
} else {
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S1P, 1);
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, S1P, 1);
}
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, TTF, 2); /* AArch64 PTW only */
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, COHACC, 1); /* IO coherent */
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, ASID16, 1); /* 16-bit ASID */
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, VMID16, 1); /* 16-bit VMID */
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, TTENDIAN, 2); /* little endian */
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, STALL_MODEL, 1); /* No stall */
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, TTF, 2); /* AArch64 PTW only */
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, COHACC, 1); /* IO coherent */
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, ASID16, 1); /* 16-bit ASID */
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, VMID16, 1); /* 16-bit VMID */
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, TTENDIAN, 2); /* little endian */
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, STALL_MODEL, 1); /* No stall */
/* terminated transaction will always be aborted/error returned */
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, TERM_MODEL, 1);
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, TERM_MODEL, 1);
/* 2-level stream table supported */
- s->idr[0] = FIELD_DP32(s->idr[0], IDR0, STLEVEL, 1);
+ bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, STLEVEL, 1);
- s->idr[1] = FIELD_DP32(s->idr[1], IDR1, SIDSIZE, SMMU_IDR1_SIDSIZE);
- s->idr[1] = FIELD_DP32(s->idr[1], IDR1, EVENTQS, SMMU_EVENTQS);
- s->idr[1] = FIELD_DP32(s->idr[1], IDR1, CMDQS, SMMU_CMDQS);
+ bk->idr[1] = FIELD_DP32(bk->idr[1], IDR1, SIDSIZE, SMMU_IDR1_SIDSIZE);
+ bk->idr[1] = FIELD_DP32(bk->idr[1], IDR1, EVENTQS, SMMU_EVENTQS);
+ bk->idr[1] = FIELD_DP32(bk->idr[1], IDR1, CMDQS, SMMU_CMDQS);
- s->idr[3] = FIELD_DP32(s->idr[3], IDR3, HAD, 1);
- if (FIELD_EX32(s->idr[0], IDR0, S2P)) {
+ bk->idr[3] = FIELD_DP32(bk->idr[3], IDR3, HAD, 1);
+ if (FIELD_EX32(bk->idr[0], IDR0, S2P)) {
/* XNX is a stage-2-specific feature */
- s->idr[3] = FIELD_DP32(s->idr[3], IDR3, XNX, 1);
+ bk->idr[3] = FIELD_DP32(bk->idr[3], IDR3, XNX, 1);
}
- s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
- s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2);
+ bk->idr[3] = FIELD_DP32(bk->idr[3], IDR3, RIL, 1);
+ bk->idr[3] = FIELD_DP32(bk->idr[3], IDR3, BBML, 2);
/* OAS: 44 bits */
- s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS_44);
+ bk->idr[5] = FIELD_DP32(bk->idr[5], IDR5, OAS, SMMU_IDR5_OAS_44);
/* 4K, 16K and 64K granule support */
- s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1);
- s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, 1);
- s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN64K, 1);
+ bk->idr[5] = FIELD_DP32(bk->idr[5], IDR5, GRAN4K, 1);
+ bk->idr[5] = FIELD_DP32(bk->idr[5], IDR5, GRAN16K, 1);
+ bk->idr[5] = FIELD_DP32(bk->idr[5], IDR5, GRAN64K, 1);
s->aidr = 0x1;
smmuv3_accel_idr_override(s);
}
static void smmuv3_reset(SMMUv3State *s)
{
- s->cmdq.base = deposit64(s->cmdq.base, 0, 5, SMMU_CMDQS);
- s->cmdq.prod = 0;
- s->cmdq.cons = 0;
- s->cmdq.entry_size = sizeof(struct Cmd);
- s->eventq.base = deposit64(s->eventq.base, 0, 5, SMMU_EVENTQS);
- s->eventq.prod = 0;
- s->eventq.cons = 0;
- s->eventq.entry_size = sizeof(struct Evt);
-
- s->features = 0;
- s->sid_split = 0;
- s->cr[0] = 0;
- s->cr0ack = 0;
- s->irq_ctrl = 0;
- s->gerror = 0;
- s->gerrorn = 0;
+ SMMUv3RegBank *bk = smmuv3_bank(s, SMMU_SEC_SID_NS);
+
+ bk->cmdq.base = deposit64(bk->cmdq.base, 0, 5, SMMU_CMDQS);
+ bk->cmdq.prod = 0;
+ bk->cmdq.cons = 0;
+ bk->cmdq.entry_size = sizeof(struct Cmd);
+ bk->eventq.base = deposit64(bk->eventq.base, 0, 5, SMMU_EVENTQS);
+ bk->eventq.prod = 0;
+ bk->eventq.cons = 0;
+ bk->eventq.entry_size = sizeof(struct Evt);
+
+ bk->features = 0;
+ bk->sid_split = 0;
+ bk->cr[0] = 0;
+ bk->cr0ack = 0;
+ bk->irq_ctrl = 0;
+ bk->gerror = 0;
+ bk->gerrorn = 0;
+ bk->gbpa = SMMU_GBPA_RESET_VAL;
+
+ s->aidr = 0x1;
s->statusr = 0;
- s->gbpa = SMMU_GBPA_RESET_VAL;
}
static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
@@ -442,7 +454,7 @@ static bool s2_pgtable_config_valid(uint8_t sl0, uint8_t t0sz, uint8_t gran)
static int decode_ste_s2_cfg(SMMUv3State *s, SMMUTransCfg *cfg,
STE *ste)
{
- uint8_t oas = FIELD_EX32(s->idr[5], IDR5, OAS);
+ uint8_t oas = FIELD_EX32(smmuv3_bank(s, SMMU_SEC_SID_NS)->idr[5], IDR5, OAS);
if (STE_S2AA64(ste) == 0x0) {
qemu_log_mask(LOG_UNIMP,
@@ -560,7 +572,8 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
STE *ste, SMMUEventInfo *event)
{
uint32_t config;
- uint8_t oas = FIELD_EX32(s->idr[5], IDR5, OAS);
+ /* OAS field only presents on NS-IDR5 so we use hardcoded SMMU_SEC_SID_NS */
+ uint8_t oas = FIELD_EX32(smmuv3_bank(s, SMMU_SEC_SID_NS)->idr[5], IDR5, OAS);
int ret;
if (!STE_VALID(ste)) {
@@ -649,9 +662,11 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
uint32_t log2size;
int strtab_size_shift;
int ret;
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
- trace_smmuv3_find_ste(sid, s->features, s->sid_split);
- log2size = FIELD_EX32(s->strtab_base_cfg, STRTAB_BASE_CFG, LOG2SIZE);
+ trace_smmuv3_find_ste(sid, bank->features, bank->sid_split);
+ log2size = FIELD_EX32(bank->strtab_base_cfg, STRTAB_BASE_CFG, LOG2SIZE);
/*
* Check SID range against both guest-configured and implementation limits
*/
@@ -659,7 +674,7 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
event->type = SMMU_EVT_C_BAD_STREAMID;
return -EINVAL;
}
- if (s->features & SMMU_FEATURE_2LVL_STE) {
+ if (bank->features & SMMU_FEATURE_2LVL_STE) {
int l1_ste_offset, l2_ste_offset, max_l2_ste, span, i;
dma_addr_t l1ptr, l2ptr;
STEDesc l1std;
@@ -668,11 +683,11 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
* Align strtab base address to table size. For this purpose, assume it
* is not bounded by SMMU_IDR1_SIDSIZE.
*/
- strtab_size_shift = MAX(5, (int)log2size - s->sid_split - 1 + 3);
- strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK &
+ strtab_size_shift = MAX(5, (int)log2size - bank->sid_split - 1 + 3);
+ strtab_base = bank->strtab_base & SMMU_BASE_ADDR_MASK &
~MAKE_64BIT_MASK(0, strtab_size_shift);
- l1_ste_offset = sid >> s->sid_split;
- l2_ste_offset = sid & ((1 << s->sid_split) - 1);
+ l1_ste_offset = sid >> bank->sid_split;
+ l2_ste_offset = sid & ((1 << bank->sid_split) - 1);
l1ptr = (dma_addr_t)(strtab_base + l1_ste_offset * sizeof(l1std));
/* TODO: guarantee 64-bit single-copy atomicity */
ret = dma_memory_read(&address_space_memory, l1ptr, &l1std,
@@ -701,7 +716,7 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
}
max_l2_ste = (1 << span) - 1;
l2ptr = l1std_l2ptr(&l1std);
- trace_smmuv3_find_ste_2lvl(s->strtab_base, l1ptr, l1_ste_offset,
+ trace_smmuv3_find_ste_2lvl(bank->strtab_base, l1ptr, l1_ste_offset,
l2ptr, l2_ste_offset, max_l2_ste);
if (l2_ste_offset > max_l2_ste) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -713,7 +728,7 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
addr = l2ptr + l2_ste_offset * sizeof(*ste);
} else {
strtab_size_shift = log2size + 5;
- strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK &
+ strtab_base = bank->strtab_base & SMMU_BASE_ADDR_MASK &
~MAKE_64BIT_MASK(0, strtab_size_shift);
addr = strtab_base + sid * sizeof(*ste);
}
@@ -732,7 +747,7 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
int i;
SMMUTranslationStatus status;
SMMUTLBEntry *entry;
- uint8_t oas = FIELD_EX32(s->idr[5], IDR5, OAS);
+ uint8_t oas = FIELD_EX32(smmuv3_bank(s, SMMU_SEC_SID_NS)->idr[5], IDR5, OAS);
if (!CD_VALID(cd) || !CD_AARCH64(cd)) {
goto bad_cd;
@@ -1054,6 +1069,8 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
SMMUv3State *s = sdev->smmu;
uint32_t sid = smmu_get_sid(sdev);
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
SMMUEventInfo event = {.type = SMMU_EVT_NONE,
.sid = sid,
.inval_ste_allowed = false};
@@ -1071,7 +1088,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
qemu_mutex_lock(&s->mutex);
if (!smmu_enabled(s)) {
- if (FIELD_EX32(s->gbpa, GBPA, ABORT)) {
+ if (FIELD_EX32(bank->gbpa, GBPA, ABORT)) {
status = SMMU_TRANS_ABORT;
} else {
status = SMMU_TRANS_DISABLE;
@@ -1295,7 +1312,9 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
{
SMMUState *bs = ARM_SMMU(s);
SMMUCmdError cmd_error = SMMU_CERROR_NONE;
- SMMUQueue *q = &s->cmdq;
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
+ SMMUQueue *q = &bank->cmdq;
SMMUCommandType type = 0;
if (!smmuv3_cmdq_enabled(s)) {
@@ -1309,7 +1328,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
*/
while (!smmuv3_q_empty(q)) {
- uint32_t pending = s->gerror ^ s->gerrorn;
+ uint32_t pending = bank->gerror ^ bank->gerrorn;
Cmd cmd;
trace_smmuv3_cmdq_consume(Q_PROD(q), Q_CONS(q),
@@ -1562,29 +1581,32 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
uint64_t data, MemTxAttrs attrs)
{
+ SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
+
switch (offset) {
case A_GERROR_IRQ_CFG0:
- s->gerror_irq_cfg0 = data;
+ bank->gerror_irq_cfg0 = data;
return MEMTX_OK;
case A_STRTAB_BASE:
- s->strtab_base = data;
+ bank->strtab_base = data;
return MEMTX_OK;
case A_CMDQ_BASE:
- s->cmdq.base = data;
- s->cmdq.log2size = extract64(s->cmdq.base, 0, 5);
- if (s->cmdq.log2size > SMMU_CMDQS) {
- s->cmdq.log2size = SMMU_CMDQS;
+ bank->cmdq.base = data;
+ bank->cmdq.log2size = extract64(bank->cmdq.base, 0, 5);
+ if (bank->cmdq.log2size > SMMU_CMDQS) {
+ bank->cmdq.log2size = SMMU_CMDQS;
}
return MEMTX_OK;
case A_EVENTQ_BASE:
- s->eventq.base = data;
- s->eventq.log2size = extract64(s->eventq.base, 0, 5);
- if (s->eventq.log2size > SMMU_EVENTQS) {
- s->eventq.log2size = SMMU_EVENTQS;
+ bank->eventq.base = data;
+ bank->eventq.log2size = extract64(bank->eventq.base, 0, 5);
+ if (bank->eventq.log2size > SMMU_EVENTQS) {
+ bank->eventq.log2size = SMMU_EVENTQS;
}
return MEMTX_OK;
case A_EVENTQ_IRQ_CFG0:
- s->eventq_irq_cfg0 = data;
+ bank->eventq_irq_cfg0 = data;
return MEMTX_OK;
default:
qemu_log_mask(LOG_UNIMP,
@@ -1598,22 +1620,24 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
uint64_t data, MemTxAttrs attrs)
{
Error *local_err = NULL;
+ SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
switch (offset) {
case A_CR0:
- s->cr[0] = data;
- s->cr0ack = data & ~SMMU_CR0_RESERVED;
+ bank->cr[0] = data;
+ bank->cr0ack = data & ~SMMU_CR0_RESERVED;
/* in case the command queue has been enabled */
smmuv3_cmdq_consume(s, &local_err);
break;
case A_CR1:
- s->cr[1] = data;
+ bank->cr[1] = data;
break;
case A_CR2:
- s->cr[2] = data;
+ bank->cr[2] = data;
break;
case A_IRQ_CTRL:
- s->irq_ctrl = data;
+ bank->irq_ctrl = data;
break;
case A_GERRORN:
smmuv3_write_gerrorn(s, data);
@@ -1624,16 +1648,16 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
smmuv3_cmdq_consume(s, &local_err);
break;
case A_GERROR_IRQ_CFG0: /* 64b */
- s->gerror_irq_cfg0 = deposit64(s->gerror_irq_cfg0, 0, 32, data);
+ bank->gerror_irq_cfg0 = deposit64(bank->gerror_irq_cfg0, 0, 32, data);
break;
case A_GERROR_IRQ_CFG0 + 4:
- s->gerror_irq_cfg0 = deposit64(s->gerror_irq_cfg0, 32, 32, data);
+ bank->gerror_irq_cfg0 = deposit64(bank->gerror_irq_cfg0, 32, 32, data);
break;
case A_GERROR_IRQ_CFG1:
- s->gerror_irq_cfg1 = data;
+ bank->gerror_irq_cfg1 = data;
break;
case A_GERROR_IRQ_CFG2:
- s->gerror_irq_cfg2 = data;
+ bank->gerror_irq_cfg2 = data;
break;
case A_GBPA:
/*
@@ -1642,67 +1666,67 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
*/
if (data & R_GBPA_UPDATE_MASK) {
/* Ignore update bit as write is synchronous. */
- s->gbpa = data & ~R_GBPA_UPDATE_MASK;
+ bank->gbpa = data & ~R_GBPA_UPDATE_MASK;
smmuv3_accel_attach_gbpa_hwpt(s, &local_err);
}
break;
case A_STRTAB_BASE: /* 64b */
- s->strtab_base = deposit64(s->strtab_base, 0, 32, data);
+ bank->strtab_base = deposit64(bank->strtab_base, 0, 32, data);
break;
case A_STRTAB_BASE + 4:
- s->strtab_base = deposit64(s->strtab_base, 32, 32, data);
+ bank->strtab_base = deposit64(bank->strtab_base, 32, 32, data);
break;
case A_STRTAB_BASE_CFG:
- s->strtab_base_cfg = data;
+ bank->strtab_base_cfg = data;
if (FIELD_EX32(data, STRTAB_BASE_CFG, FMT) == 1) {
- s->sid_split = FIELD_EX32(data, STRTAB_BASE_CFG, SPLIT);
- s->features |= SMMU_FEATURE_2LVL_STE;
+ bank->sid_split = FIELD_EX32(data, STRTAB_BASE_CFG, SPLIT);
+ bank->features |= SMMU_FEATURE_2LVL_STE;
}
break;
case A_CMDQ_BASE: /* 64b */
- s->cmdq.base = deposit64(s->cmdq.base, 0, 32, data);
- s->cmdq.log2size = extract64(s->cmdq.base, 0, 5);
- if (s->cmdq.log2size > SMMU_CMDQS) {
- s->cmdq.log2size = SMMU_CMDQS;
+ bank->cmdq.base = deposit64(bank->cmdq.base, 0, 32, data);
+ bank->cmdq.log2size = extract64(bank->cmdq.base, 0, 5);
+ if (bank->cmdq.log2size > SMMU_CMDQS) {
+ bank->cmdq.log2size = SMMU_CMDQS;
}
break;
case A_CMDQ_BASE + 4: /* 64b */
- s->cmdq.base = deposit64(s->cmdq.base, 32, 32, data);
+ bank->cmdq.base = deposit64(bank->cmdq.base, 32, 32, data);
break;
case A_CMDQ_PROD:
- s->cmdq.prod = data;
+ bank->cmdq.prod = data;
smmuv3_cmdq_consume(s, &local_err);
break;
case A_CMDQ_CONS:
- s->cmdq.cons = data;
+ bank->cmdq.cons = data;
break;
case A_EVENTQ_BASE: /* 64b */
- s->eventq.base = deposit64(s->eventq.base, 0, 32, data);
- s->eventq.log2size = extract64(s->eventq.base, 0, 5);
- if (s->eventq.log2size > SMMU_EVENTQS) {
- s->eventq.log2size = SMMU_EVENTQS;
+ bank->eventq.base = deposit64(bank->eventq.base, 0, 32, data);
+ bank->eventq.log2size = extract64(bank->eventq.base, 0, 5);
+ if (bank->eventq.log2size > SMMU_EVENTQS) {
+ bank->eventq.log2size = SMMU_EVENTQS;
}
break;
case A_EVENTQ_BASE + 4:
- s->eventq.base = deposit64(s->eventq.base, 32, 32, data);
+ bank->eventq.base = deposit64(bank->eventq.base, 32, 32, data);
break;
case A_EVENTQ_PROD:
- s->eventq.prod = data;
+ bank->eventq.prod = data;
break;
case A_EVENTQ_CONS:
- s->eventq.cons = data;
+ bank->eventq.cons = data;
break;
case A_EVENTQ_IRQ_CFG0: /* 64b */
- s->eventq_irq_cfg0 = deposit64(s->eventq_irq_cfg0, 0, 32, data);
+ bank->eventq_irq_cfg0 = deposit64(bank->eventq_irq_cfg0, 0, 32, data);
break;
case A_EVENTQ_IRQ_CFG0 + 4:
- s->eventq_irq_cfg0 = deposit64(s->eventq_irq_cfg0, 32, 32, data);
+ bank->eventq_irq_cfg0 = deposit64(bank->eventq_irq_cfg0, 32, 32, data);
break;
case A_EVENTQ_IRQ_CFG1:
- s->eventq_irq_cfg1 = data;
+ bank->eventq_irq_cfg1 = data;
break;
case A_EVENTQ_IRQ_CFG2:
- s->eventq_irq_cfg2 = data;
+ bank->eventq_irq_cfg2 = data;
break;
default:
qemu_log_mask(LOG_UNIMP,
@@ -1746,18 +1770,21 @@ static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t data,
static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
uint64_t *data, MemTxAttrs attrs)
{
+ SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
+
switch (offset) {
case A_GERROR_IRQ_CFG0:
- *data = s->gerror_irq_cfg0;
+ *data = bank->gerror_irq_cfg0;
return MEMTX_OK;
case A_STRTAB_BASE:
- *data = s->strtab_base;
+ *data = bank->strtab_base;
return MEMTX_OK;
case A_CMDQ_BASE:
- *data = s->cmdq.base;
+ *data = bank->cmdq.base;
return MEMTX_OK;
case A_EVENTQ_BASE:
- *data = s->eventq.base;
+ *data = bank->eventq.base;
return MEMTX_OK;
default:
*data = 0;
@@ -1771,12 +1798,15 @@ static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
uint64_t *data, MemTxAttrs attrs)
{
+ SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
+ SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
+
switch (offset) {
case A_IDREGS ... A_IDREGS + 0x2f:
*data = smmuv3_idreg(offset - A_IDREGS);
return MEMTX_OK;
case A_IDR0 ... A_IDR5:
- *data = s->idr[(offset - A_IDR0) / 4];
+ *data = bank->idr[(offset - A_IDR0) / 4];
return MEMTX_OK;
case A_IIDR:
*data = s->iidr;
@@ -1785,77 +1815,77 @@ static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
*data = s->aidr;
return MEMTX_OK;
case A_CR0:
- *data = s->cr[0];
+ *data = bank->cr[0];
return MEMTX_OK;
case A_CR0ACK:
- *data = s->cr0ack;
+ *data = bank->cr0ack;
return MEMTX_OK;
case A_CR1:
- *data = s->cr[1];
+ *data = bank->cr[1];
return MEMTX_OK;
case A_CR2:
- *data = s->cr[2];
+ *data = bank->cr[2];
return MEMTX_OK;
case A_STATUSR:
*data = s->statusr;
return MEMTX_OK;
case A_GBPA:
- *data = s->gbpa;
+ *data = bank->gbpa;
return MEMTX_OK;
case A_IRQ_CTRL:
case A_IRQ_CTRL_ACK:
- *data = s->irq_ctrl;
+ *data = bank->irq_ctrl;
return MEMTX_OK;
case A_GERROR:
- *data = s->gerror;
+ *data = bank->gerror;
return MEMTX_OK;
case A_GERRORN:
- *data = s->gerrorn;
+ *data = bank->gerrorn;
return MEMTX_OK;
case A_GERROR_IRQ_CFG0: /* 64b */
- *data = extract64(s->gerror_irq_cfg0, 0, 32);
+ *data = extract64(bank->gerror_irq_cfg0, 0, 32);
return MEMTX_OK;
case A_GERROR_IRQ_CFG0 + 4:
- *data = extract64(s->gerror_irq_cfg0, 32, 32);
+ *data = extract64(bank->gerror_irq_cfg0, 32, 32);
return MEMTX_OK;
case A_GERROR_IRQ_CFG1:
- *data = s->gerror_irq_cfg1;
+ *data = bank->gerror_irq_cfg1;
return MEMTX_OK;
case A_GERROR_IRQ_CFG2:
- *data = s->gerror_irq_cfg2;
+ *data = bank->gerror_irq_cfg2;
return MEMTX_OK;
case A_STRTAB_BASE: /* 64b */
- *data = extract64(s->strtab_base, 0, 32);
+ *data = extract64(bank->strtab_base, 0, 32);
return MEMTX_OK;
case A_STRTAB_BASE + 4: /* 64b */
- *data = extract64(s->strtab_base, 32, 32);
+ *data = extract64(bank->strtab_base, 32, 32);
return MEMTX_OK;
case A_STRTAB_BASE_CFG:
- *data = s->strtab_base_cfg;
+ *data = bank->strtab_base_cfg;
return MEMTX_OK;
case A_CMDQ_BASE: /* 64b */
- *data = extract64(s->cmdq.base, 0, 32);
+ *data = extract64(bank->cmdq.base, 0, 32);
return MEMTX_OK;
case A_CMDQ_BASE + 4:
- *data = extract64(s->cmdq.base, 32, 32);
+ *data = extract64(bank->cmdq.base, 32, 32);
return MEMTX_OK;
case A_CMDQ_PROD:
- *data = s->cmdq.prod;
+ *data = bank->cmdq.prod;
return MEMTX_OK;
case A_CMDQ_CONS:
- *data = s->cmdq.cons;
+ *data = bank->cmdq.cons;
return MEMTX_OK;
case A_EVENTQ_BASE: /* 64b */
- *data = extract64(s->eventq.base, 0, 32);
+ *data = extract64(bank->eventq.base, 0, 32);
return MEMTX_OK;
case A_EVENTQ_BASE + 4: /* 64b */
- *data = extract64(s->eventq.base, 32, 32);
+ *data = extract64(bank->eventq.base, 32, 32);
return MEMTX_OK;
case A_EVENTQ_PROD:
- *data = s->eventq.prod;
+ *data = bank->eventq.prod;
return MEMTX_OK;
case A_EVENTQ_CONS:
- *data = s->eventq.cons;
+ *data = bank->eventq.cons;
return MEMTX_OK;
default:
*data = 0;
@@ -2039,9 +2069,10 @@ static const VMStateDescription vmstate_smmuv3_queue = {
static bool smmuv3_gbpa_needed(void *opaque)
{
SMMUv3State *s = opaque;
+ SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
/* Only migrate GBPA if it has different reset value. */
- return s->gbpa != SMMU_GBPA_RESET_VAL;
+ return bank->gbpa != SMMU_GBPA_RESET_VAL;
}
static const VMStateDescription vmstate_gbpa = {
@@ -2050,7 +2081,7 @@ static const VMStateDescription vmstate_gbpa = {
.minimum_version_id = 1,
.needed = smmuv3_gbpa_needed,
.fields = (const VMStateField[]) {
- VMSTATE_UINT32(gbpa, SMMUv3State),
+ VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].gbpa, SMMUv3State),
VMSTATE_END_OF_LIST()
}
};
@@ -2061,27 +2092,29 @@ static const VMStateDescription vmstate_smmuv3 = {
.minimum_version_id = 1,
.priority = MIG_PRI_IOMMU,
.fields = (const VMStateField[]) {
- VMSTATE_UINT32(features, SMMUv3State),
+ VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].features, SMMUv3State),
VMSTATE_UINT8(sid_size, SMMUv3State),
- VMSTATE_UINT8(sid_split, SMMUv3State),
+ VMSTATE_UINT8(bank[SMMU_SEC_SID_NS].sid_split, SMMUv3State),
- VMSTATE_UINT32_ARRAY(cr, SMMUv3State, 3),
- VMSTATE_UINT32(cr0ack, SMMUv3State),
+ VMSTATE_UINT32_ARRAY(bank[SMMU_SEC_SID_NS].cr, SMMUv3State, 3),
+ VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].cr0ack, SMMUv3State),
VMSTATE_UINT32(statusr, SMMUv3State),
- VMSTATE_UINT32(irq_ctrl, SMMUv3State),
- VMSTATE_UINT32(gerror, SMMUv3State),
- VMSTATE_UINT32(gerrorn, SMMUv3State),
- VMSTATE_UINT64(gerror_irq_cfg0, SMMUv3State),
- VMSTATE_UINT32(gerror_irq_cfg1, SMMUv3State),
- VMSTATE_UINT32(gerror_irq_cfg2, SMMUv3State),
- VMSTATE_UINT64(strtab_base, SMMUv3State),
- VMSTATE_UINT32(strtab_base_cfg, SMMUv3State),
- VMSTATE_UINT64(eventq_irq_cfg0, SMMUv3State),
- VMSTATE_UINT32(eventq_irq_cfg1, SMMUv3State),
- VMSTATE_UINT32(eventq_irq_cfg2, SMMUv3State),
-
- VMSTATE_STRUCT(cmdq, SMMUv3State, 0, vmstate_smmuv3_queue, SMMUQueue),
- VMSTATE_STRUCT(eventq, SMMUv3State, 0, vmstate_smmuv3_queue, SMMUQueue),
+ VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].irq_ctrl, SMMUv3State),
+ VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].gerror, SMMUv3State),
+ VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].gerrorn, SMMUv3State),
+ VMSTATE_UINT64(bank[SMMU_SEC_SID_NS].gerror_irq_cfg0, SMMUv3State),
+ VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].gerror_irq_cfg1, SMMUv3State),
+ VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].gerror_irq_cfg2, SMMUv3State),
+ VMSTATE_UINT64(bank[SMMU_SEC_SID_NS].strtab_base, SMMUv3State),
+ VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].strtab_base_cfg, SMMUv3State),
+ VMSTATE_UINT64(bank[SMMU_SEC_SID_NS].eventq_irq_cfg0, SMMUv3State),
+ VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].eventq_irq_cfg1, SMMUv3State),
+ VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].eventq_irq_cfg2, SMMUv3State),
+
+ VMSTATE_STRUCT(bank[SMMU_SEC_SID_NS].cmdq, SMMUv3State, 0,
+ vmstate_smmuv3_queue, SMMUQueue),
+ VMSTATE_STRUCT(bank[SMMU_SEC_SID_NS].eventq, SMMUv3State, 0,
+ vmstate_smmuv3_queue, SMMUQueue),
VMSTATE_END_OF_LIST(),
},
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index 7b975abc25a..6ea40f6b074 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -40,6 +40,12 @@
#define CACHED_ENTRY_TO_ADDR(ent, addr) ((ent)->entry.translated_addr + \
((addr) & (ent)->entry.addr_mask))
+/* StreamID Security state */
+typedef enum SMMUSecSID {
+ SMMU_SEC_SID_NS = 0,
+ SMMU_SEC_SID_NUM,
+} SMMUSecSID;
+
/*
* Page table walk error types
*/
diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
index 26b2fc42fd9..d07bdfa1f27 100644
--- a/include/hw/arm/smmuv3.h
+++ b/include/hw/arm/smmuv3.h
@@ -32,19 +32,13 @@ typedef struct SMMUQueue {
uint8_t log2size;
} SMMUQueue;
-struct SMMUv3State {
- SMMUState smmu_state;
-
+typedef struct SMMUv3RegBank {
uint32_t features;
- uint8_t sid_size;
uint8_t sid_split;
uint32_t idr[6];
- uint32_t iidr;
- uint32_t aidr;
uint32_t cr[3];
uint32_t cr0ack;
- uint32_t statusr;
uint32_t gbpa;
uint32_t irq_ctrl;
uint32_t gerror;
@@ -59,6 +53,17 @@ struct SMMUv3State {
uint32_t eventq_irq_cfg2;
SMMUQueue eventq, cmdq;
+} SMMUv3RegBank;
+
+struct SMMUv3State {
+ SMMUState smmu_state;
+
+ uint8_t sid_size;
+ uint32_t iidr;
+ uint32_t aidr;
+ uint32_t statusr;
+
+ SMMUv3RegBank bank[SMMU_SEC_SID_NUM];
qemu_irq irq[4];
QemuMutex mutex;
@@ -94,7 +99,14 @@ struct SMMUv3Class {
#define TYPE_ARM_SMMUV3 "arm-smmuv3"
OBJECT_DECLARE_TYPE(SMMUv3State, SMMUv3Class, ARM_SMMUV3)
-#define STAGE1_SUPPORTED(s) FIELD_EX32(s->idr[0], IDR0, S1P)
-#define STAGE2_SUPPORTED(s) FIELD_EX32(s->idr[0], IDR0, S2P)
+#define STAGE1_SUPPORTED(s) \
+ FIELD_EX32((s)->bank[SMMU_SEC_SID_NS].idr[0], IDR0, S1P)
+#define STAGE2_SUPPORTED(s) \
+ FIELD_EX32((s)->bank[SMMU_SEC_SID_NS].idr[0], IDR0, S2P)
+
+static inline SMMUv3RegBank *smmuv3_bank(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ return &s->bank[sec_sid];
+}
#endif
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 04/31] hw/arm/smmuv3: Introduce banked registers for SMMUv3 state
2026-02-21 10:02 ` [RFC v4 04/31] hw/arm/smmuv3: Introduce banked registers for SMMUv3 state Tao Tang
@ 2026-02-25 20:26 ` Pierrick Bouvier
2026-02-27 14:38 ` Mostafa Saleh
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 20:26 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:02 AM, Tao Tang wrote:
> Rework the SMMUv3 state management by introducing a banked register
> structure. This is a purely mechanical refactoring with no functional
> changes.
>
> To support multiple security states, a new enum, SMMUSecSID, is
> introduced to identify each state, sticking to the spec terminology.
>
> A new structure, SMMUv3RegBank, is then defined to hold the state
> for a single security context. The main SMMUv3State now contains an
> array of these banks, indexed by SMMUSecSID. This avoids the need for
> separate fields for non-secure and future secure registers.
>
> All existing code, which handles only the Non-secure state, is updated
> to access its state via s->bank[SMMU_SEC_SID_NS]. A local bank helper
> pointer is used where it improves readability.
>
> Function signatures and logic remain untouched in this commit to
> isolate the structural changes and simplify review. This is the
> foundational step for building multi-security-state support.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> ---
> hw/arm/smmuv3-accel.c | 42 +++--
> hw/arm/smmuv3-internal.h | 24 ++-
> hw/arm/smmuv3.c | 345 +++++++++++++++++++----------------
> include/hw/arm/smmu-common.h | 6 +
> include/hw/arm/smmuv3.h | 30 ++-
> 5 files changed, 257 insertions(+), 190 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 04/31] hw/arm/smmuv3: Introduce banked registers for SMMUv3 state
2026-02-21 10:02 ` [RFC v4 04/31] hw/arm/smmuv3: Introduce banked registers for SMMUv3 state Tao Tang
2026-02-25 20:26 ` Pierrick Bouvier
@ 2026-02-27 14:38 ` Mostafa Saleh
2026-03-01 13:44 ` Tao Tang
1 sibling, 1 reply; 136+ messages in thread
From: Mostafa Saleh @ 2026-02-27 14:38 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sat, Feb 21, 2026 at 06:02:23PM +0800, Tao Tang wrote:
> Rework the SMMUv3 state management by introducing a banked register
> structure. This is a purely mechanical refactoring with no functional
> changes.
>
> To support multiple security states, a new enum, SMMUSecSID, is
> introduced to identify each state, sticking to the spec terminology.
>
> A new structure, SMMUv3RegBank, is then defined to hold the state
> for a single security context. The main SMMUv3State now contains an
> array of these banks, indexed by SMMUSecSID. This avoids the need for
> separate fields for non-secure and future secure registers.
>
> All existing code, which handles only the Non-secure state, is updated
> to access its state via s->bank[SMMU_SEC_SID_NS]. A local bank helper
> pointer is used where it improves readability.
>
> Function signatures and logic remain untouched in this commit to
> isolate the structural changes and simplify review. This is the
> foundational step for building multi-security-state support.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
There are a few warning from scripts/checkpatch.pl, plus some other
nits I mentioned, otherwise:
Reviewed-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmuv3-accel.c | 42 +++--
> hw/arm/smmuv3-internal.h | 24 ++-
> hw/arm/smmuv3.c | 345 +++++++++++++++++++----------------
> include/hw/arm/smmu-common.h | 6 +
> include/hw/arm/smmuv3.h | 30 ++-
> 5 files changed, 257 insertions(+), 190 deletions(-)
>
> diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
> index f5cd4df336a..30d4b38c0a3 100644
> --- a/hw/arm/smmuv3-accel.c
> +++ b/hw/arm/smmuv3-accel.c
> @@ -40,19 +40,20 @@ smmuv3_accel_check_hw_compatible(SMMUv3State *s,
> struct iommu_hw_info_arm_smmuv3 *info,
> Error **errp)
> {
> + SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
> /* QEMU SMMUv3 supports both linear and 2-level stream tables */
> if (FIELD_EX32(info->idr[0], IDR0, STLEVEL) !=
> - FIELD_EX32(s->idr[0], IDR0, STLEVEL)) {
> + FIELD_EX32(bank->idr[0], IDR0, STLEVEL)) {
> error_setg(errp, "Host SMMUv3 Stream Table format mismatch "
> "(host STLEVEL=%u, QEMU STLEVEL=%u)",
> FIELD_EX32(info->idr[0], IDR0, STLEVEL),
> - FIELD_EX32(s->idr[0], IDR0, STLEVEL));
> + FIELD_EX32(bank->idr[0], IDR0, STLEVEL));
> return false;
> }
>
> /* QEMU SMMUv3 supports only little-endian translation table walks */
> if (FIELD_EX32(info->idr[0], IDR0, TTENDIAN) >
> - FIELD_EX32(s->idr[0], IDR0, TTENDIAN)) {
> + FIELD_EX32(bank->idr[0], IDR0, TTENDIAN)) {
> error_setg(errp, "Host SMMUv3 doesn't support Little-endian "
> "translation table");
> return false;
> @@ -60,7 +61,7 @@ smmuv3_accel_check_hw_compatible(SMMUv3State *s,
>
> /* QEMU SMMUv3 supports only AArch64 translation table format */
> if (FIELD_EX32(info->idr[0], IDR0, TTF) <
> - FIELD_EX32(s->idr[0], IDR0, TTF)) {
> + FIELD_EX32(bank->idr[0], IDR0, TTF)) {
> error_setg(errp, "Host SMMUv3 doesn't support AArch64 translation "
> "table format");
> return false;
> @@ -68,53 +69,53 @@ smmuv3_accel_check_hw_compatible(SMMUv3State *s,
>
> /* QEMU SMMUv3 supports SIDSIZE 16 */
> if (FIELD_EX32(info->idr[1], IDR1, SIDSIZE) <
> - FIELD_EX32(s->idr[1], IDR1, SIDSIZE)) {
> + FIELD_EX32(bank->idr[1], IDR1, SIDSIZE)) {
> error_setg(errp, "Host SMMUv3 SIDSIZE not compatible "
> "(host=%u, QEMU=%u)",
> FIELD_EX32(info->idr[1], IDR1, SIDSIZE),
> - FIELD_EX32(s->idr[1], IDR1, SIDSIZE));
> + FIELD_EX32(bank->idr[1], IDR1, SIDSIZE));
> return false;
> }
>
> /* Check SSIDSIZE value opted-in is compatible with Host SMMUv3 SSIDSIZE */
> if (FIELD_EX32(info->idr[1], IDR1, SSIDSIZE) <
> - FIELD_EX32(s->idr[1], IDR1, SSIDSIZE)) {
> + FIELD_EX32(bank->idr[1], IDR1, SSIDSIZE)) {
> error_setg(errp, "Host SMMUv3 SSIDSIZE not compatible "
> "(host=%u, QEMU=%u)",
> FIELD_EX32(info->idr[1], IDR1, SSIDSIZE),
> - FIELD_EX32(s->idr[1], IDR1, SSIDSIZE));
> + FIELD_EX32(bank->idr[1], IDR1, SSIDSIZE));
> return false;
> }
>
> /* User can disable QEMU SMMUv3 Range Invalidation support */
> if (FIELD_EX32(info->idr[3], IDR3, RIL) <
> - FIELD_EX32(s->idr[3], IDR3, RIL)) {
> + FIELD_EX32(bank->idr[3], IDR3, RIL)) {
> error_setg(errp, "Host SMMUv3 doesn't support Range Invalidation");
> return false;
> }
> /* Check OAS value opted is compatible with Host SMMUv3 IPA */
> if (FIELD_EX32(info->idr[5], IDR5, OAS) <
> - FIELD_EX32(s->idr[5], IDR5, OAS)) {
> + FIELD_EX32(bank->idr[5], IDR5, OAS)) {
> error_setg(errp, "Host SMMUv3 supports only %d-bit IPA, but the vSMMU "
> "OAS implies %d-bit IPA",
> smmuv3_oas_bits(FIELD_EX32(info->idr[5], IDR5, OAS)),
> - smmuv3_oas_bits(FIELD_EX32(s->idr[5], IDR5, OAS)));
> + smmuv3_oas_bits(FIELD_EX32(bank->idr[5], IDR5, OAS)));
> return false;
> }
>
> /* QEMU SMMUv3 supports GRAN4K/GRAN16K/GRAN64K translation granules */
> if (FIELD_EX32(info->idr[5], IDR5, GRAN4K) !=
> - FIELD_EX32(s->idr[5], IDR5, GRAN4K)) {
> + FIELD_EX32(bank->idr[5], IDR5, GRAN4K)) {
> error_setg(errp, "Host SMMUv3 doesn't support 4K translation granule");
> return false;
> }
> if (FIELD_EX32(info->idr[5], IDR5, GRAN16K) !=
> - FIELD_EX32(s->idr[5], IDR5, GRAN16K)) {
> + FIELD_EX32(bank->idr[5], IDR5, GRAN16K)) {
> error_setg(errp, "Host SMMUv3 doesn't support 16K translation granule");
> return false;
> }
> if (FIELD_EX32(info->idr[5], IDR5, GRAN64K) !=
> - FIELD_EX32(s->idr[5], IDR5, GRAN64K)) {
> + FIELD_EX32(bank->idr[5], IDR5, GRAN64K)) {
> error_setg(errp, "Host SMMUv3 doesn't support 64K translation granule");
> return false;
> }
> @@ -168,7 +169,8 @@ static SMMUv3AccelDevice *smmuv3_accel_get_dev(SMMUState *bs, SMMUPciBus *sbus,
>
> static uint32_t smmuv3_accel_gbpa_hwpt(SMMUv3State *s, SMMUv3AccelState *accel)
> {
> - return FIELD_EX32(s->gbpa, GBPA, ABORT) ?
> + SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
> + return FIELD_EX32(bank->gbpa, GBPA, ABORT) ?
> accel->abort_hwpt_id : accel->bypass_hwpt_id;
> }
>
> @@ -687,22 +689,24 @@ void smmuv3_accel_idr_override(SMMUv3State *s)
> return;
> }
>
> + SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
Sometimes you have:
SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
Others
SMMUv3RegBank *bk = smmuv3_bank(s, SMMU_SEC_SID_NS);
It would be helpful if naming is consistent.
> +
> /* By default QEMU SMMUv3 has RIL. Update IDR3 if user has disabled it */
> - s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, s->ril);
> + bank->idr[3] = FIELD_DP32(bank->idr[3], IDR3, RIL, s->ril);
>
> /* QEMU SMMUv3 has no ATS. Advertise ATS if opt-in by property */
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, ATS, s->ats);
> + bank->idr[0] = FIELD_DP32(bank->idr[0], IDR0, ATS, s->ats);
>
> /* Advertise 48-bit OAS in IDR5 when requested (default is 44 bits). */
> if (s->oas == SMMU_OAS_48BIT) {
> - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS_48);
> + bank->idr[5] = FIELD_DP32(bank->idr[5], IDR5, OAS, SMMU_IDR5_OAS_48);
> }
>
> /*
> * By default QEMU SMMUv3 has no SubstreamID support. Update IDR1 if user
> * has enabled it.
> */
> - s->idr[1] = FIELD_DP32(s->idr[1], IDR1, SSIDSIZE, s->ssidsize);
> + bank->idr[1] = FIELD_DP32(bank->idr[1], IDR1, SSIDSIZE, s->ssidsize);
> }
>
> /* Based on SMUUv3 GPBA.ABORT configuration, attach a corresponding HWPT */
> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> index ebdb4ebae67..deb1ef60e87 100644
> --- a/hw/arm/smmuv3-internal.h
> +++ b/hw/arm/smmuv3-internal.h
> @@ -41,7 +41,9 @@ typedef enum SMMUTranslationClass {
>
> static inline int smmu_enabled(SMMUv3State *s)
> {
> - return FIELD_EX32(s->cr[0], CR0, SMMUEN);
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> + return FIELD_EX32(bank->cr[0], CR0, SMMUEN);
> }
>
> /* Command Queue Entry */
> @@ -69,12 +71,16 @@ static inline uint32_t smmuv3_idreg(int regoffset)
>
> static inline bool smmuv3_eventq_irq_enabled(SMMUv3State *s)
> {
> - return FIELD_EX32(s->irq_ctrl, IRQ_CTRL, EVENTQ_IRQEN);
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> + return FIELD_EX32(bank->irq_ctrl, IRQ_CTRL, EVENTQ_IRQEN);
> }
>
> static inline bool smmuv3_gerror_irq_enabled(SMMUv3State *s)
> {
> - return FIELD_EX32(s->irq_ctrl, IRQ_CTRL, GERROR_IRQEN);
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> + return FIELD_EX32(bank->irq_ctrl, IRQ_CTRL, GERROR_IRQEN);
> }
>
> /* Queue Handling */
> @@ -119,17 +125,23 @@ static inline void queue_cons_incr(SMMUQueue *q)
>
> static inline bool smmuv3_cmdq_enabled(SMMUv3State *s)
> {
> - return FIELD_EX32(s->cr[0], CR0, CMDQEN);
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> + return FIELD_EX32(bank->cr[0], CR0, CMDQEN);
> }
>
> static inline bool smmuv3_eventq_enabled(SMMUv3State *s)
> {
> - return FIELD_EX32(s->cr[0], CR0, EVENTQEN);
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> + return FIELD_EX32(bank->cr[0], CR0, EVENTQEN);
> }
>
> static inline void smmu_write_cmdq_err(SMMUv3State *s, uint32_t err_type)
> {
> - s->cmdq.cons = FIELD_DP32(s->cmdq.cons, CMDQ_CONS, ERR, err_type);
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> + bank->cmdq.cons = FIELD_DP32(bank->cmdq.cons, CMDQ_CONS, ERR, err_type);
> }
>
> static const char *cmd_stringify[] = {
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index c08d58c5790..5511585601d 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -52,6 +52,8 @@
> static void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq,
> uint32_t gerror_mask)
> {
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>
> bool pulse = false;
>
> @@ -67,15 +69,15 @@ static void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq,
> break;
> case SMMU_IRQ_GERROR:
> {
> - uint32_t pending = s->gerror ^ s->gerrorn;
> + uint32_t pending = bank->gerror ^ bank->gerrorn;
> uint32_t new_gerrors = ~pending & gerror_mask;
>
> if (!new_gerrors) {
> /* only toggle non pending errors */
> return;
> }
> - s->gerror ^= new_gerrors;
> - trace_smmuv3_write_gerror(new_gerrors, s->gerror);
> + bank->gerror ^= new_gerrors;
> + trace_smmuv3_write_gerror(new_gerrors, bank->gerror);
>
> pulse = smmuv3_gerror_irq_enabled(s);
> break;
> @@ -89,8 +91,10 @@ static void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq,
>
> static void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_gerrorn)
> {
> - uint32_t pending = s->gerror ^ s->gerrorn;
> - uint32_t toggled = s->gerrorn ^ new_gerrorn;
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> + uint32_t pending = bank->gerror ^ bank->gerrorn;
> + uint32_t toggled = bank->gerrorn ^ new_gerrorn;
>
> if (toggled & ~pending) {
> qemu_log_mask(LOG_GUEST_ERROR,
> @@ -102,9 +106,9 @@ static void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_gerrorn)
> * We do not raise any error in case guest toggles bits corresponding
> * to not active IRQs (CONSTRAINED UNPREDICTABLE)
> */
> - s->gerrorn = new_gerrorn;
> + bank->gerrorn = new_gerrorn;
>
> - trace_smmuv3_write_gerrorn(toggled & pending, s->gerrorn);
> + trace_smmuv3_write_gerrorn(toggled & pending, bank->gerrorn);
> }
>
> static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd)
> @@ -146,7 +150,9 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
>
> static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
> {
> - SMMUQueue *q = &s->eventq;
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> + SMMUQueue *q = &bank->eventq;
> MemTxResult r;
>
> if (!smmuv3_eventq_enabled(s)) {
> @@ -266,69 +272,75 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
> */
> static void smmuv3_init_id_regs(SMMUv3State *s)
> {
> + SMMUv3RegBank *bk = smmuv3_bank(s, SMMU_SEC_SID_NS);
> +
> /* Based on sys property, the stages supported in smmu will be advertised.*/
> if (s->stage && !strcmp("2", s->stage)) {
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S2P, 1);
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, S2P, 1);
> } else if (s->stage && !strcmp("nested", s->stage)) {
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S1P, 1);
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S2P, 1);
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, S1P, 1);
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, S2P, 1);
> } else {
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S1P, 1);
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, S1P, 1);
> }
>
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, TTF, 2); /* AArch64 PTW only */
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, COHACC, 1); /* IO coherent */
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, ASID16, 1); /* 16-bit ASID */
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, VMID16, 1); /* 16-bit VMID */
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, TTENDIAN, 2); /* little endian */
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, STALL_MODEL, 1); /* No stall */
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, TTF, 2); /* AArch64 PTW only */
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, COHACC, 1); /* IO coherent */
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, ASID16, 1); /* 16-bit ASID */
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, VMID16, 1); /* 16-bit VMID */
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, TTENDIAN, 2); /* little endian */
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, STALL_MODEL, 1); /* No stall */
> /* terminated transaction will always be aborted/error returned */
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, TERM_MODEL, 1);
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, TERM_MODEL, 1);
> /* 2-level stream table supported */
> - s->idr[0] = FIELD_DP32(s->idr[0], IDR0, STLEVEL, 1);
> + bk->idr[0] = FIELD_DP32(bk->idr[0], IDR0, STLEVEL, 1);
>
> - s->idr[1] = FIELD_DP32(s->idr[1], IDR1, SIDSIZE, SMMU_IDR1_SIDSIZE);
> - s->idr[1] = FIELD_DP32(s->idr[1], IDR1, EVENTQS, SMMU_EVENTQS);
> - s->idr[1] = FIELD_DP32(s->idr[1], IDR1, CMDQS, SMMU_CMDQS);
> + bk->idr[1] = FIELD_DP32(bk->idr[1], IDR1, SIDSIZE, SMMU_IDR1_SIDSIZE);
> + bk->idr[1] = FIELD_DP32(bk->idr[1], IDR1, EVENTQS, SMMU_EVENTQS);
> + bk->idr[1] = FIELD_DP32(bk->idr[1], IDR1, CMDQS, SMMU_CMDQS);
>
> - s->idr[3] = FIELD_DP32(s->idr[3], IDR3, HAD, 1);
> - if (FIELD_EX32(s->idr[0], IDR0, S2P)) {
> + bk->idr[3] = FIELD_DP32(bk->idr[3], IDR3, HAD, 1);
> + if (FIELD_EX32(bk->idr[0], IDR0, S2P)) {
> /* XNX is a stage-2-specific feature */
> - s->idr[3] = FIELD_DP32(s->idr[3], IDR3, XNX, 1);
> + bk->idr[3] = FIELD_DP32(bk->idr[3], IDR3, XNX, 1);
> }
> - s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
> - s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2);
> + bk->idr[3] = FIELD_DP32(bk->idr[3], IDR3, RIL, 1);
> + bk->idr[3] = FIELD_DP32(bk->idr[3], IDR3, BBML, 2);
>
> /* OAS: 44 bits */
> - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS_44);
> + bk->idr[5] = FIELD_DP32(bk->idr[5], IDR5, OAS, SMMU_IDR5_OAS_44);
> /* 4K, 16K and 64K granule support */
> - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN4K, 1);
> - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN16K, 1);
> - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, GRAN64K, 1);
> + bk->idr[5] = FIELD_DP32(bk->idr[5], IDR5, GRAN4K, 1);
> + bk->idr[5] = FIELD_DP32(bk->idr[5], IDR5, GRAN16K, 1);
> + bk->idr[5] = FIELD_DP32(bk->idr[5], IDR5, GRAN64K, 1);
> s->aidr = 0x1;
> smmuv3_accel_idr_override(s);
> }
>
> static void smmuv3_reset(SMMUv3State *s)
> {
> - s->cmdq.base = deposit64(s->cmdq.base, 0, 5, SMMU_CMDQS);
> - s->cmdq.prod = 0;
> - s->cmdq.cons = 0;
> - s->cmdq.entry_size = sizeof(struct Cmd);
> - s->eventq.base = deposit64(s->eventq.base, 0, 5, SMMU_EVENTQS);
> - s->eventq.prod = 0;
> - s->eventq.cons = 0;
> - s->eventq.entry_size = sizeof(struct Evt);
> -
> - s->features = 0;
> - s->sid_split = 0;
> - s->cr[0] = 0;
> - s->cr0ack = 0;
> - s->irq_ctrl = 0;
> - s->gerror = 0;
> - s->gerrorn = 0;
> + SMMUv3RegBank *bk = smmuv3_bank(s, SMMU_SEC_SID_NS);
> +
> + bk->cmdq.base = deposit64(bk->cmdq.base, 0, 5, SMMU_CMDQS);
> + bk->cmdq.prod = 0;
> + bk->cmdq.cons = 0;
> + bk->cmdq.entry_size = sizeof(struct Cmd);
> + bk->eventq.base = deposit64(bk->eventq.base, 0, 5, SMMU_EVENTQS);
> + bk->eventq.prod = 0;
> + bk->eventq.cons = 0;
> + bk->eventq.entry_size = sizeof(struct Evt);
> +
> + bk->features = 0;
> + bk->sid_split = 0;
> + bk->cr[0] = 0;
> + bk->cr0ack = 0;
> + bk->irq_ctrl = 0;
> + bk->gerror = 0;
> + bk->gerrorn = 0;
> + bk->gbpa = SMMU_GBPA_RESET_VAL;
> +
> + s->aidr = 0x1;
> s->statusr = 0;
> - s->gbpa = SMMU_GBPA_RESET_VAL;
> }
>
> static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
> @@ -442,7 +454,7 @@ static bool s2_pgtable_config_valid(uint8_t sl0, uint8_t t0sz, uint8_t gran)
> static int decode_ste_s2_cfg(SMMUv3State *s, SMMUTransCfg *cfg,
> STE *ste)
> {
> - uint8_t oas = FIELD_EX32(s->idr[5], IDR5, OAS);
> + uint8_t oas = FIELD_EX32(smmuv3_bank(s, SMMU_SEC_SID_NS)->idr[5], IDR5, OAS);
>
> if (STE_S2AA64(ste) == 0x0) {
> qemu_log_mask(LOG_UNIMP,
> @@ -560,7 +572,8 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
> STE *ste, SMMUEventInfo *event)
> {
> uint32_t config;
> - uint8_t oas = FIELD_EX32(s->idr[5], IDR5, OAS);
> + /* OAS field only presents on NS-IDR5 so we use hardcoded SMMU_SEC_SID_NS */
> + uint8_t oas = FIELD_EX32(smmuv3_bank(s, SMMU_SEC_SID_NS)->idr[5], IDR5, OAS);
> int ret;
>
> if (!STE_VALID(ste)) {
> @@ -649,9 +662,11 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
> uint32_t log2size;
> int strtab_size_shift;
> int ret;
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>
> - trace_smmuv3_find_ste(sid, s->features, s->sid_split);
> - log2size = FIELD_EX32(s->strtab_base_cfg, STRTAB_BASE_CFG, LOG2SIZE);
> + trace_smmuv3_find_ste(sid, bank->features, bank->sid_split);
> + log2size = FIELD_EX32(bank->strtab_base_cfg, STRTAB_BASE_CFG, LOG2SIZE);
> /*
> * Check SID range against both guest-configured and implementation limits
> */
> @@ -659,7 +674,7 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
> event->type = SMMU_EVT_C_BAD_STREAMID;
> return -EINVAL;
> }
> - if (s->features & SMMU_FEATURE_2LVL_STE) {
> + if (bank->features & SMMU_FEATURE_2LVL_STE) {
> int l1_ste_offset, l2_ste_offset, max_l2_ste, span, i;
> dma_addr_t l1ptr, l2ptr;
> STEDesc l1std;
> @@ -668,11 +683,11 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
> * Align strtab base address to table size. For this purpose, assume it
> * is not bounded by SMMU_IDR1_SIDSIZE.
> */
> - strtab_size_shift = MAX(5, (int)log2size - s->sid_split - 1 + 3);
> - strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK &
> + strtab_size_shift = MAX(5, (int)log2size - bank->sid_split - 1 + 3);
> + strtab_base = bank->strtab_base & SMMU_BASE_ADDR_MASK &
> ~MAKE_64BIT_MASK(0, strtab_size_shift);
> - l1_ste_offset = sid >> s->sid_split;
> - l2_ste_offset = sid & ((1 << s->sid_split) - 1);
> + l1_ste_offset = sid >> bank->sid_split;
> + l2_ste_offset = sid & ((1 << bank->sid_split) - 1);
> l1ptr = (dma_addr_t)(strtab_base + l1_ste_offset * sizeof(l1std));
> /* TODO: guarantee 64-bit single-copy atomicity */
> ret = dma_memory_read(&address_space_memory, l1ptr, &l1std,
> @@ -701,7 +716,7 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
> }
> max_l2_ste = (1 << span) - 1;
> l2ptr = l1std_l2ptr(&l1std);
> - trace_smmuv3_find_ste_2lvl(s->strtab_base, l1ptr, l1_ste_offset,
> + trace_smmuv3_find_ste_2lvl(bank->strtab_base, l1ptr, l1_ste_offset,
> l2ptr, l2_ste_offset, max_l2_ste);
> if (l2_ste_offset > max_l2_ste) {
> qemu_log_mask(LOG_GUEST_ERROR,
> @@ -713,7 +728,7 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
> addr = l2ptr + l2_ste_offset * sizeof(*ste);
> } else {
> strtab_size_shift = log2size + 5;
> - strtab_base = s->strtab_base & SMMU_BASE_ADDR_MASK &
> + strtab_base = bank->strtab_base & SMMU_BASE_ADDR_MASK &
> ~MAKE_64BIT_MASK(0, strtab_size_shift);
> addr = strtab_base + sid * sizeof(*ste);
> }
> @@ -732,7 +747,7 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
> int i;
> SMMUTranslationStatus status;
> SMMUTLBEntry *entry;
> - uint8_t oas = FIELD_EX32(s->idr[5], IDR5, OAS);
> + uint8_t oas = FIELD_EX32(smmuv3_bank(s, SMMU_SEC_SID_NS)->idr[5], IDR5, OAS);
>
> if (!CD_VALID(cd) || !CD_AARCH64(cd)) {
> goto bad_cd;
> @@ -1054,6 +1069,8 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
> SMMUv3State *s = sdev->smmu;
> uint32_t sid = smmu_get_sid(sdev);
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> SMMUEventInfo event = {.type = SMMU_EVT_NONE,
> .sid = sid,
> .inval_ste_allowed = false};
> @@ -1071,7 +1088,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> qemu_mutex_lock(&s->mutex);
>
> if (!smmu_enabled(s)) {
> - if (FIELD_EX32(s->gbpa, GBPA, ABORT)) {
> + if (FIELD_EX32(bank->gbpa, GBPA, ABORT)) {
> status = SMMU_TRANS_ABORT;
> } else {
> status = SMMU_TRANS_DISABLE;
> @@ -1295,7 +1312,9 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> {
> SMMUState *bs = ARM_SMMU(s);
> SMMUCmdError cmd_error = SMMU_CERROR_NONE;
> - SMMUQueue *q = &s->cmdq;
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> + SMMUQueue *q = &bank->cmdq;
> SMMUCommandType type = 0;
>
> if (!smmuv3_cmdq_enabled(s)) {
> @@ -1309,7 +1328,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> */
>
> while (!smmuv3_q_empty(q)) {
> - uint32_t pending = s->gerror ^ s->gerrorn;
> + uint32_t pending = bank->gerror ^ bank->gerrorn;
> Cmd cmd;
>
> trace_smmuv3_cmdq_consume(Q_PROD(q), Q_CONS(q),
> @@ -1562,29 +1581,32 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
> uint64_t data, MemTxAttrs attrs)
> {
> + SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
> +
> switch (offset) {
> case A_GERROR_IRQ_CFG0:
> - s->gerror_irq_cfg0 = data;
> + bank->gerror_irq_cfg0 = data;
> return MEMTX_OK;
> case A_STRTAB_BASE:
> - s->strtab_base = data;
> + bank->strtab_base = data;
> return MEMTX_OK;
> case A_CMDQ_BASE:
> - s->cmdq.base = data;
> - s->cmdq.log2size = extract64(s->cmdq.base, 0, 5);
> - if (s->cmdq.log2size > SMMU_CMDQS) {
> - s->cmdq.log2size = SMMU_CMDQS;
> + bank->cmdq.base = data;
> + bank->cmdq.log2size = extract64(bank->cmdq.base, 0, 5);
> + if (bank->cmdq.log2size > SMMU_CMDQS) {
> + bank->cmdq.log2size = SMMU_CMDQS;
> }
> return MEMTX_OK;
> case A_EVENTQ_BASE:
> - s->eventq.base = data;
> - s->eventq.log2size = extract64(s->eventq.base, 0, 5);
> - if (s->eventq.log2size > SMMU_EVENTQS) {
> - s->eventq.log2size = SMMU_EVENTQS;
> + bank->eventq.base = data;
> + bank->eventq.log2size = extract64(bank->eventq.base, 0, 5);
> + if (bank->eventq.log2size > SMMU_EVENTQS) {
> + bank->eventq.log2size = SMMU_EVENTQS;
> }
> return MEMTX_OK;
> case A_EVENTQ_IRQ_CFG0:
> - s->eventq_irq_cfg0 = data;
> + bank->eventq_irq_cfg0 = data;
> return MEMTX_OK;
> default:
> qemu_log_mask(LOG_UNIMP,
> @@ -1598,22 +1620,24 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
> uint64_t data, MemTxAttrs attrs)
> {
> Error *local_err = NULL;
> + SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
>
> switch (offset) {
> case A_CR0:
> - s->cr[0] = data;
> - s->cr0ack = data & ~SMMU_CR0_RESERVED;
> + bank->cr[0] = data;
> + bank->cr0ack = data & ~SMMU_CR0_RESERVED;
> /* in case the command queue has been enabled */
> smmuv3_cmdq_consume(s, &local_err);
> break;
> case A_CR1:
> - s->cr[1] = data;
> + bank->cr[1] = data;
> break;
> case A_CR2:
> - s->cr[2] = data;
> + bank->cr[2] = data;
> break;
> case A_IRQ_CTRL:
> - s->irq_ctrl = data;
> + bank->irq_ctrl = data;
> break;
> case A_GERRORN:
> smmuv3_write_gerrorn(s, data);
> @@ -1624,16 +1648,16 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
> smmuv3_cmdq_consume(s, &local_err);
> break;
> case A_GERROR_IRQ_CFG0: /* 64b */
> - s->gerror_irq_cfg0 = deposit64(s->gerror_irq_cfg0, 0, 32, data);
> + bank->gerror_irq_cfg0 = deposit64(bank->gerror_irq_cfg0, 0, 32, data);
> break;
> case A_GERROR_IRQ_CFG0 + 4:
> - s->gerror_irq_cfg0 = deposit64(s->gerror_irq_cfg0, 32, 32, data);
> + bank->gerror_irq_cfg0 = deposit64(bank->gerror_irq_cfg0, 32, 32, data);
> break;
> case A_GERROR_IRQ_CFG1:
> - s->gerror_irq_cfg1 = data;
> + bank->gerror_irq_cfg1 = data;
> break;
> case A_GERROR_IRQ_CFG2:
> - s->gerror_irq_cfg2 = data;
> + bank->gerror_irq_cfg2 = data;
> break;
> case A_GBPA:
> /*
> @@ -1642,67 +1666,67 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
> */
> if (data & R_GBPA_UPDATE_MASK) {
> /* Ignore update bit as write is synchronous. */
> - s->gbpa = data & ~R_GBPA_UPDATE_MASK;
> + bank->gbpa = data & ~R_GBPA_UPDATE_MASK;
> smmuv3_accel_attach_gbpa_hwpt(s, &local_err);
> }
> break;
> case A_STRTAB_BASE: /* 64b */
> - s->strtab_base = deposit64(s->strtab_base, 0, 32, data);
> + bank->strtab_base = deposit64(bank->strtab_base, 0, 32, data);
> break;
> case A_STRTAB_BASE + 4:
> - s->strtab_base = deposit64(s->strtab_base, 32, 32, data);
> + bank->strtab_base = deposit64(bank->strtab_base, 32, 32, data);
> break;
> case A_STRTAB_BASE_CFG:
> - s->strtab_base_cfg = data;
> + bank->strtab_base_cfg = data;
> if (FIELD_EX32(data, STRTAB_BASE_CFG, FMT) == 1) {
> - s->sid_split = FIELD_EX32(data, STRTAB_BASE_CFG, SPLIT);
> - s->features |= SMMU_FEATURE_2LVL_STE;
> + bank->sid_split = FIELD_EX32(data, STRTAB_BASE_CFG, SPLIT);
> + bank->features |= SMMU_FEATURE_2LVL_STE;
> }
> break;
> case A_CMDQ_BASE: /* 64b */
> - s->cmdq.base = deposit64(s->cmdq.base, 0, 32, data);
> - s->cmdq.log2size = extract64(s->cmdq.base, 0, 5);
> - if (s->cmdq.log2size > SMMU_CMDQS) {
> - s->cmdq.log2size = SMMU_CMDQS;
> + bank->cmdq.base = deposit64(bank->cmdq.base, 0, 32, data);
> + bank->cmdq.log2size = extract64(bank->cmdq.base, 0, 5);
> + if (bank->cmdq.log2size > SMMU_CMDQS) {
> + bank->cmdq.log2size = SMMU_CMDQS;
> }
> break;
> case A_CMDQ_BASE + 4: /* 64b */
> - s->cmdq.base = deposit64(s->cmdq.base, 32, 32, data);
> + bank->cmdq.base = deposit64(bank->cmdq.base, 32, 32, data);
> break;
> case A_CMDQ_PROD:
> - s->cmdq.prod = data;
> + bank->cmdq.prod = data;
> smmuv3_cmdq_consume(s, &local_err);
> break;
> case A_CMDQ_CONS:
> - s->cmdq.cons = data;
> + bank->cmdq.cons = data;
> break;
> case A_EVENTQ_BASE: /* 64b */
> - s->eventq.base = deposit64(s->eventq.base, 0, 32, data);
> - s->eventq.log2size = extract64(s->eventq.base, 0, 5);
> - if (s->eventq.log2size > SMMU_EVENTQS) {
> - s->eventq.log2size = SMMU_EVENTQS;
> + bank->eventq.base = deposit64(bank->eventq.base, 0, 32, data);
> + bank->eventq.log2size = extract64(bank->eventq.base, 0, 5);
> + if (bank->eventq.log2size > SMMU_EVENTQS) {
> + bank->eventq.log2size = SMMU_EVENTQS;
> }
> break;
> case A_EVENTQ_BASE + 4:
> - s->eventq.base = deposit64(s->eventq.base, 32, 32, data);
> + bank->eventq.base = deposit64(bank->eventq.base, 32, 32, data);
> break;
> case A_EVENTQ_PROD:
> - s->eventq.prod = data;
> + bank->eventq.prod = data;
> break;
> case A_EVENTQ_CONS:
> - s->eventq.cons = data;
> + bank->eventq.cons = data;
> break;
> case A_EVENTQ_IRQ_CFG0: /* 64b */
> - s->eventq_irq_cfg0 = deposit64(s->eventq_irq_cfg0, 0, 32, data);
> + bank->eventq_irq_cfg0 = deposit64(bank->eventq_irq_cfg0, 0, 32, data);
> break;
> case A_EVENTQ_IRQ_CFG0 + 4:
> - s->eventq_irq_cfg0 = deposit64(s->eventq_irq_cfg0, 32, 32, data);
> + bank->eventq_irq_cfg0 = deposit64(bank->eventq_irq_cfg0, 32, 32, data);
> break;
> case A_EVENTQ_IRQ_CFG1:
> - s->eventq_irq_cfg1 = data;
> + bank->eventq_irq_cfg1 = data;
> break;
> case A_EVENTQ_IRQ_CFG2:
> - s->eventq_irq_cfg2 = data;
> + bank->eventq_irq_cfg2 = data;
> break;
> default:
> qemu_log_mask(LOG_UNIMP,
> @@ -1746,18 +1770,21 @@ static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t data,
> static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
> uint64_t *data, MemTxAttrs attrs)
> {
> + SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
> +
> switch (offset) {
> case A_GERROR_IRQ_CFG0:
> - *data = s->gerror_irq_cfg0;
> + *data = bank->gerror_irq_cfg0;
> return MEMTX_OK;
> case A_STRTAB_BASE:
> - *data = s->strtab_base;
> + *data = bank->strtab_base;
> return MEMTX_OK;
> case A_CMDQ_BASE:
> - *data = s->cmdq.base;
> + *data = bank->cmdq.base;
> return MEMTX_OK;
> case A_EVENTQ_BASE:
> - *data = s->eventq.base;
> + *data = bank->eventq.base;
> return MEMTX_OK;
> default:
> *data = 0;
> @@ -1771,12 +1798,15 @@ static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
> static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
> uint64_t *data, MemTxAttrs attrs)
> {
> + SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
> + SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
> +
> switch (offset) {
> case A_IDREGS ... A_IDREGS + 0x2f:
> *data = smmuv3_idreg(offset - A_IDREGS);
> return MEMTX_OK;
> case A_IDR0 ... A_IDR5:
> - *data = s->idr[(offset - A_IDR0) / 4];
> + *data = bank->idr[(offset - A_IDR0) / 4];
> return MEMTX_OK;
> case A_IIDR:
> *data = s->iidr;
> @@ -1785,77 +1815,77 @@ static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
> *data = s->aidr;
> return MEMTX_OK;
> case A_CR0:
> - *data = s->cr[0];
> + *data = bank->cr[0];
> return MEMTX_OK;
> case A_CR0ACK:
> - *data = s->cr0ack;
> + *data = bank->cr0ack;
> return MEMTX_OK;
> case A_CR1:
> - *data = s->cr[1];
> + *data = bank->cr[1];
> return MEMTX_OK;
> case A_CR2:
> - *data = s->cr[2];
> + *data = bank->cr[2];
> return MEMTX_OK;
> case A_STATUSR:
> *data = s->statusr;
> return MEMTX_OK;
> case A_GBPA:
> - *data = s->gbpa;
> + *data = bank->gbpa;
> return MEMTX_OK;
> case A_IRQ_CTRL:
> case A_IRQ_CTRL_ACK:
> - *data = s->irq_ctrl;
> + *data = bank->irq_ctrl;
> return MEMTX_OK;
> case A_GERROR:
> - *data = s->gerror;
> + *data = bank->gerror;
> return MEMTX_OK;
> case A_GERRORN:
> - *data = s->gerrorn;
> + *data = bank->gerrorn;
> return MEMTX_OK;
> case A_GERROR_IRQ_CFG0: /* 64b */
> - *data = extract64(s->gerror_irq_cfg0, 0, 32);
> + *data = extract64(bank->gerror_irq_cfg0, 0, 32);
> return MEMTX_OK;
> case A_GERROR_IRQ_CFG0 + 4:
> - *data = extract64(s->gerror_irq_cfg0, 32, 32);
> + *data = extract64(bank->gerror_irq_cfg0, 32, 32);
> return MEMTX_OK;
> case A_GERROR_IRQ_CFG1:
> - *data = s->gerror_irq_cfg1;
> + *data = bank->gerror_irq_cfg1;
> return MEMTX_OK;
> case A_GERROR_IRQ_CFG2:
> - *data = s->gerror_irq_cfg2;
> + *data = bank->gerror_irq_cfg2;
> return MEMTX_OK;
> case A_STRTAB_BASE: /* 64b */
> - *data = extract64(s->strtab_base, 0, 32);
> + *data = extract64(bank->strtab_base, 0, 32);
> return MEMTX_OK;
> case A_STRTAB_BASE + 4: /* 64b */
> - *data = extract64(s->strtab_base, 32, 32);
> + *data = extract64(bank->strtab_base, 32, 32);
> return MEMTX_OK;
> case A_STRTAB_BASE_CFG:
> - *data = s->strtab_base_cfg;
> + *data = bank->strtab_base_cfg;
> return MEMTX_OK;
> case A_CMDQ_BASE: /* 64b */
> - *data = extract64(s->cmdq.base, 0, 32);
> + *data = extract64(bank->cmdq.base, 0, 32);
> return MEMTX_OK;
> case A_CMDQ_BASE + 4:
> - *data = extract64(s->cmdq.base, 32, 32);
> + *data = extract64(bank->cmdq.base, 32, 32);
> return MEMTX_OK;
> case A_CMDQ_PROD:
> - *data = s->cmdq.prod;
> + *data = bank->cmdq.prod;
> return MEMTX_OK;
> case A_CMDQ_CONS:
> - *data = s->cmdq.cons;
> + *data = bank->cmdq.cons;
> return MEMTX_OK;
> case A_EVENTQ_BASE: /* 64b */
> - *data = extract64(s->eventq.base, 0, 32);
> + *data = extract64(bank->eventq.base, 0, 32);
> return MEMTX_OK;
> case A_EVENTQ_BASE + 4: /* 64b */
> - *data = extract64(s->eventq.base, 32, 32);
> + *data = extract64(bank->eventq.base, 32, 32);
> return MEMTX_OK;
> case A_EVENTQ_PROD:
> - *data = s->eventq.prod;
> + *data = bank->eventq.prod;
> return MEMTX_OK;
> case A_EVENTQ_CONS:
> - *data = s->eventq.cons;
> + *data = bank->eventq.cons;
> return MEMTX_OK;
> default:
> *data = 0;
> @@ -2039,9 +2069,10 @@ static const VMStateDescription vmstate_smmuv3_queue = {
> static bool smmuv3_gbpa_needed(void *opaque)
> {
> SMMUv3State *s = opaque;
> + SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
>
> /* Only migrate GBPA if it has different reset value. */
> - return s->gbpa != SMMU_GBPA_RESET_VAL;
> + return bank->gbpa != SMMU_GBPA_RESET_VAL;
> }
>
> static const VMStateDescription vmstate_gbpa = {
> @@ -2050,7 +2081,7 @@ static const VMStateDescription vmstate_gbpa = {
> .minimum_version_id = 1,
> .needed = smmuv3_gbpa_needed,
> .fields = (const VMStateField[]) {
> - VMSTATE_UINT32(gbpa, SMMUv3State),
> + VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].gbpa, SMMUv3State),
> VMSTATE_END_OF_LIST()
> }
> };
> @@ -2061,27 +2092,29 @@ static const VMStateDescription vmstate_smmuv3 = {
> .minimum_version_id = 1,
> .priority = MIG_PRI_IOMMU,
> .fields = (const VMStateField[]) {
> - VMSTATE_UINT32(features, SMMUv3State),
> + VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].features, SMMUv3State),
> VMSTATE_UINT8(sid_size, SMMUv3State),
> - VMSTATE_UINT8(sid_split, SMMUv3State),
> + VMSTATE_UINT8(bank[SMMU_SEC_SID_NS].sid_split, SMMUv3State),
>
> - VMSTATE_UINT32_ARRAY(cr, SMMUv3State, 3),
> - VMSTATE_UINT32(cr0ack, SMMUv3State),
> + VMSTATE_UINT32_ARRAY(bank[SMMU_SEC_SID_NS].cr, SMMUv3State, 3),
> + VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].cr0ack, SMMUv3State),
> VMSTATE_UINT32(statusr, SMMUv3State),
> - VMSTATE_UINT32(irq_ctrl, SMMUv3State),
> - VMSTATE_UINT32(gerror, SMMUv3State),
> - VMSTATE_UINT32(gerrorn, SMMUv3State),
> - VMSTATE_UINT64(gerror_irq_cfg0, SMMUv3State),
> - VMSTATE_UINT32(gerror_irq_cfg1, SMMUv3State),
> - VMSTATE_UINT32(gerror_irq_cfg2, SMMUv3State),
> - VMSTATE_UINT64(strtab_base, SMMUv3State),
> - VMSTATE_UINT32(strtab_base_cfg, SMMUv3State),
> - VMSTATE_UINT64(eventq_irq_cfg0, SMMUv3State),
> - VMSTATE_UINT32(eventq_irq_cfg1, SMMUv3State),
> - VMSTATE_UINT32(eventq_irq_cfg2, SMMUv3State),
> -
> - VMSTATE_STRUCT(cmdq, SMMUv3State, 0, vmstate_smmuv3_queue, SMMUQueue),
> - VMSTATE_STRUCT(eventq, SMMUv3State, 0, vmstate_smmuv3_queue, SMMUQueue),
> + VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].irq_ctrl, SMMUv3State),
> + VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].gerror, SMMUv3State),
> + VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].gerrorn, SMMUv3State),
> + VMSTATE_UINT64(bank[SMMU_SEC_SID_NS].gerror_irq_cfg0, SMMUv3State),
> + VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].gerror_irq_cfg1, SMMUv3State),
> + VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].gerror_irq_cfg2, SMMUv3State),
> + VMSTATE_UINT64(bank[SMMU_SEC_SID_NS].strtab_base, SMMUv3State),
> + VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].strtab_base_cfg, SMMUv3State),
> + VMSTATE_UINT64(bank[SMMU_SEC_SID_NS].eventq_irq_cfg0, SMMUv3State),
> + VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].eventq_irq_cfg1, SMMUv3State),
> + VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].eventq_irq_cfg2, SMMUv3State),
> +
> + VMSTATE_STRUCT(bank[SMMU_SEC_SID_NS].cmdq, SMMUv3State, 0,
> + vmstate_smmuv3_queue, SMMUQueue),
> + VMSTATE_STRUCT(bank[SMMU_SEC_SID_NS].eventq, SMMUv3State, 0,
> + vmstate_smmuv3_queue, SMMUQueue),
>
> VMSTATE_END_OF_LIST(),
> },
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index 7b975abc25a..6ea40f6b074 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -40,6 +40,12 @@
> #define CACHED_ENTRY_TO_ADDR(ent, addr) ((ent)->entry.translated_addr + \
> ((addr) & (ent)->entry.addr_mask))
>
> +/* StreamID Security state */
> +typedef enum SMMUSecSID {
> + SMMU_SEC_SID_NS = 0,
> + SMMU_SEC_SID_NUM,
> +} SMMUSecSID;
> +
> /*
> * Page table walk error types
> */
> diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
> index 26b2fc42fd9..d07bdfa1f27 100644
> --- a/include/hw/arm/smmuv3.h
> +++ b/include/hw/arm/smmuv3.h
> @@ -32,19 +32,13 @@ typedef struct SMMUQueue {
> uint8_t log2size;
> } SMMUQueue;
>
> -struct SMMUv3State {
> - SMMUState smmu_state;
> -
> +typedef struct SMMUv3RegBank {
> uint32_t features;
> - uint8_t sid_size;
> uint8_t sid_split;
>
> uint32_t idr[6];
> - uint32_t iidr;
> - uint32_t aidr;
> uint32_t cr[3];
> uint32_t cr0ack;
> - uint32_t statusr;
> uint32_t gbpa;
> uint32_t irq_ctrl;
> uint32_t gerror;
> @@ -59,6 +53,17 @@ struct SMMUv3State {
> uint32_t eventq_irq_cfg2;
>
> SMMUQueue eventq, cmdq;
> +} SMMUv3RegBank;
> +
> +struct SMMUv3State {
> + SMMUState smmu_state;
> +
> + uint8_t sid_size;
> + uint32_t iidr;
> + uint32_t aidr;
> + uint32_t statusr;
> +
> + SMMUv3RegBank bank[SMMU_SEC_SID_NUM];
>
> qemu_irq irq[4];
> QemuMutex mutex;
> @@ -94,7 +99,14 @@ struct SMMUv3Class {
> #define TYPE_ARM_SMMUV3 "arm-smmuv3"
> OBJECT_DECLARE_TYPE(SMMUv3State, SMMUv3Class, ARM_SMMUV3)
>
> -#define STAGE1_SUPPORTED(s) FIELD_EX32(s->idr[0], IDR0, S1P)
> -#define STAGE2_SUPPORTED(s) FIELD_EX32(s->idr[0], IDR0, S2P)
> +#define STAGE1_SUPPORTED(s) \
> + FIELD_EX32((s)->bank[SMMU_SEC_SID_NS].idr[0], IDR0, S1P)
> +#define STAGE2_SUPPORTED(s) \
> + FIELD_EX32((s)->bank[SMMU_SEC_SID_NS].idr[0], IDR0, S2P)
> +
> +static inline SMMUv3RegBank *smmuv3_bank(SMMUv3State *s, SMMUSecSID sec_sid)
> +{
> + return &s->bank[sec_sid];
> +}
>
If this is a macro you can use in other cases as in state structs as
it currently inlined in:
VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].irq_ctrl, SMMUv3State),
Thanks,
Mostafa
> #endif
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 04/31] hw/arm/smmuv3: Introduce banked registers for SMMUv3 state
2026-02-27 14:38 ` Mostafa Saleh
@ 2026-03-01 13:44 ` Tao Tang
2026-03-02 10:16 ` Mostafa Saleh
0 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-03-01 13:44 UTC (permalink / raw)
To: Mostafa Saleh
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
Hi Mostafa,
On 2026/2/27 PM10:38, Mostafa Saleh wrote:
> On Sat, Feb 21, 2026 at 06:02:23PM +0800, Tao Tang wrote:
>> Rework the SMMUv3 state management by introducing a banked register
>> structure. This is a purely mechanical refactoring with no functional
>> changes.
>>
>> To support multiple security states, a new enum, SMMUSecSID, is
>> introduced to identify each state, sticking to the spec terminology.
>>
>> A new structure, SMMUv3RegBank, is then defined to hold the state
>> for a single security context. The main SMMUv3State now contains an
>> array of these banks, indexed by SMMUSecSID. This avoids the need for
>> separate fields for non-secure and future secure registers.
>>
>> All existing code, which handles only the Non-secure state, is updated
>> to access its state via s->bank[SMMU_SEC_SID_NS]. A local bank helper
>> pointer is used where it improves readability.
>>
>> Function signatures and logic remain untouched in this commit to
>> isolate the structural changes and simplify review. This is the
>> foundational step for building multi-security-state support.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> There are a few warning from scripts/checkpatch.pl, plus some other
> nits I mentioned, otherwise:
> Reviewed-by: Mostafa Saleh <smostafa@google.com>
>
>
>> ---
>> hw/arm/smmuv3-accel.c | 42 +++--
>> hw/arm/smmuv3-internal.h | 24 ++-
>> hw/arm/smmuv3.c | 345 +++++++++++++++++++----------------
>> include/hw/arm/smmu-common.h | 6 +
>> include/hw/arm/smmuv3.h | 30 ++-
>> 5 files changed, 257 insertions(+), 190 deletions(-)
>>
>> ------------------------------<snip>------------------------------
>>
>>
>>
>> ------------------------------<snip>------------------------------
>>
>> @@ -687,22 +689,24 @@ void smmuv3_accel_idr_override(SMMUv3State *s)
>> return;
>> }
>>
>> + SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
> Sometimes you have:
> SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
> Others
> SMMUv3RegBank *bk = smmuv3_bank(s, SMMU_SEC_SID_NS);
>
> It would be helpful if naming is consistent.
Apologies for not switching to plain text only in Thunderbird in the
previous reply email, which made the formatting look a bit strange.
I'll unify this definition across all affected places in V5, and also
fix style warnings you mentioned previously.
>> ------------------------------<snip>------------------------------
>>
>>
>>
>> ------------------------------<snip>------------------------------
>> @@ -94,7 +99,14 @@ struct SMMUv3Class {
>> #define TYPE_ARM_SMMUV3 "arm-smmuv3"
>> OBJECT_DECLARE_TYPE(SMMUv3State, SMMUv3Class, ARM_SMMUV3)
>>
>> -#define STAGE1_SUPPORTED(s) FIELD_EX32(s->idr[0], IDR0, S1P)
>> -#define STAGE2_SUPPORTED(s) FIELD_EX32(s->idr[0], IDR0, S2P)
>> +#define STAGE1_SUPPORTED(s) \
>> + FIELD_EX32((s)->bank[SMMU_SEC_SID_NS].idr[0], IDR0, S1P)
>> +#define STAGE2_SUPPORTED(s) \
>> + FIELD_EX32((s)->bank[SMMU_SEC_SID_NS].idr[0], IDR0, S2P)
>> +
>> +static inline SMMUv3RegBank *smmuv3_bank(SMMUv3State *s, SMMUSecSID sec_sid)
>> +{
>> + return &s->bank[sec_sid];
>> +}
>>
> If this is a macro you can use in other cases as in state structs as
> it currently inlined in:
> VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].irq_ctrl, SMMUv3State),
My understanding is that VMSTATE_* wants an offsetof() ( VMSTATE_UINT32
-> VMSTATE_INT32_V -> VMSTATE_SINGLE -> VMSTATE_SINGLE_TEST ->
vmstate_offset_value ->offsetof ), so maybe we could not directly reuse
the runtime helper there. At runtime, smmuv3_bank() needs a real
`SMMUv3State *s` to compute the actual address of the selected bank
(`&s->bank[sec_sid]`), which is different from a compile-time field offset.
A small compromise that works for both is to define a field-path macro
and then take its address in smmuv3_bank():
```C
/* Field-path macro (offsetof-friendly) */
#define SMMUV3_BANK_F(_sid) bank[(_sid)]
#define SMMUV3_NS_BANK_F SMMUV3_BANK_F(SMMU_SEC_SID_NS)
static inline SMMUv3RegBank *smmuv3_bank(SMMUv3State *s, SMMUSecSID sec_sid)
{
return &s->SMMUV3_BANK_F(sec_sid);
}
/* VMSTATE uses the field-path macro directly */
VMSTATE_UINT32(SMMUV3_NS_BANK_F.irq_ctrl, SMMUv3State);
...
```
How do you think about it?
>
> Thanks,
> Mostafa
>
Thanks for your review.
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 04/31] hw/arm/smmuv3: Introduce banked registers for SMMUv3 state
2026-03-01 13:44 ` Tao Tang
@ 2026-03-02 10:16 ` Mostafa Saleh
0 siblings, 0 replies; 136+ messages in thread
From: Mostafa Saleh @ 2026-03-02 10:16 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sun, Mar 01, 2026 at 09:44:32PM +0800, Tao Tang wrote:
> Hi Mostafa,
>
> On 2026/2/27 PM10:38, Mostafa Saleh wrote:
> > On Sat, Feb 21, 2026 at 06:02:23PM +0800, Tao Tang wrote:
> > > Rework the SMMUv3 state management by introducing a banked register
> > > structure. This is a purely mechanical refactoring with no functional
> > > changes.
> > >
> > > To support multiple security states, a new enum, SMMUSecSID, is
> > > introduced to identify each state, sticking to the spec terminology.
> > >
> > > A new structure, SMMUv3RegBank, is then defined to hold the state
> > > for a single security context. The main SMMUv3State now contains an
> > > array of these banks, indexed by SMMUSecSID. This avoids the need for
> > > separate fields for non-secure and future secure registers.
> > >
> > > All existing code, which handles only the Non-secure state, is updated
> > > to access its state via s->bank[SMMU_SEC_SID_NS]. A local bank helper
> > > pointer is used where it improves readability.
> > >
> > > Function signatures and logic remain untouched in this commit to
> > > isolate the structural changes and simplify review. This is the
> > > foundational step for building multi-security-state support.
> > >
> > > Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> > > Reviewed-by: Eric Auger <eric.auger@redhat.com>
> > There are a few warning from scripts/checkpatch.pl, plus some other
> > nits I mentioned, otherwise:
> > Reviewed-by: Mostafa Saleh <smostafa@google.com>
> >
> >
> > > ---
> > > hw/arm/smmuv3-accel.c | 42 +++--
> > > hw/arm/smmuv3-internal.h | 24 ++-
> > > hw/arm/smmuv3.c | 345 +++++++++++++++++++----------------
> > > include/hw/arm/smmu-common.h | 6 +
> > > include/hw/arm/smmuv3.h | 30 ++-
> > > 5 files changed, 257 insertions(+), 190 deletions(-)
> > >
> > > ------------------------------<snip>------------------------------
> > >
> > >
> > >
> > > ------------------------------<snip>------------------------------
> > > @@ -687,22 +689,24 @@ void smmuv3_accel_idr_override(SMMUv3State *s)
> > > return;
> > > }
> > > + SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
> > Sometimes you have:
> > SMMUv3RegBank *bank = smmuv3_bank(s, SMMU_SEC_SID_NS);
> > Others
> > SMMUv3RegBank *bk = smmuv3_bank(s, SMMU_SEC_SID_NS);
> >
> > It would be helpful if naming is consistent.
>
>
> Apologies for not switching to plain text only in Thunderbird in the
> previous reply email, which made the formatting look a bit strange.
>
>
> I'll unify this definition across all affected places in V5, and also fix
> style warnings you mentioned previously.
>
>
> > > ------------------------------<snip>------------------------------
> > >
> > >
> > >
> > > ------------------------------<snip>------------------------------
> > > @@ -94,7 +99,14 @@ struct SMMUv3Class {
> > > #define TYPE_ARM_SMMUV3 "arm-smmuv3"
> > > OBJECT_DECLARE_TYPE(SMMUv3State, SMMUv3Class, ARM_SMMUV3)
> > > -#define STAGE1_SUPPORTED(s) FIELD_EX32(s->idr[0], IDR0, S1P)
> > > -#define STAGE2_SUPPORTED(s) FIELD_EX32(s->idr[0], IDR0, S2P)
> > > +#define STAGE1_SUPPORTED(s) \
> > > + FIELD_EX32((s)->bank[SMMU_SEC_SID_NS].idr[0], IDR0, S1P)
> > > +#define STAGE2_SUPPORTED(s) \
> > > + FIELD_EX32((s)->bank[SMMU_SEC_SID_NS].idr[0], IDR0, S2P)
> > > +
> > > +static inline SMMUv3RegBank *smmuv3_bank(SMMUv3State *s, SMMUSecSID sec_sid)
> > > +{
> > > + return &s->bank[sec_sid];
> > > +}
> > >
> > If this is a macro you can use in other cases as in state structs as
> > it currently inlined in:
> > VMSTATE_UINT32(bank[SMMU_SEC_SID_NS].irq_ctrl, SMMUv3State),
>
>
> My understanding is that VMSTATE_* wants an offsetof() ( VMSTATE_UINT32 ->
> VMSTATE_INT32_V -> VMSTATE_SINGLE -> VMSTATE_SINGLE_TEST ->
> vmstate_offset_value ->offsetof ), so maybe we could not directly reuse the
> runtime helper there. At runtime, smmuv3_bank() needs a real `SMMUv3State
> *s` to compute the actual address of the selected bank
> (`&s->bank[sec_sid]`), which is different from a compile-time field offset.
>
> A small compromise that works for both is to define a field-path macro and
> then take its address in smmuv3_bank():
I see, I missed that, in that case we can just keep it as is, no need to
change.
Thanks,
Mostafa
>
>
> ```C
>
> /* Field-path macro (offsetof-friendly) */
> #define SMMUV3_BANK_F(_sid) bank[(_sid)]
> #define SMMUV3_NS_BANK_F SMMUV3_BANK_F(SMMU_SEC_SID_NS)
>
> static inline SMMUv3RegBank *smmuv3_bank(SMMUv3State *s, SMMUSecSID sec_sid)
> {
> return &s->SMMUV3_BANK_F(sec_sid);
> }
>
> /* VMSTATE uses the field-path macro directly */
> VMSTATE_UINT32(SMMUV3_NS_BANK_F.irq_ctrl, SMMUv3State);
>
> ...
>
> ```
>
>
> How do you think about it?
>
>
> >
> > Thanks,
> > Mostafa
> >
>
> Thanks for your review.
>
> Tao
>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 05/31] hw/arm/smmuv3: Thread SEC_SID through helper APIs
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (3 preceding siblings ...)
2026-02-21 10:02 ` [RFC v4 04/31] hw/arm/smmuv3: Introduce banked registers for SMMUv3 state Tao Tang
@ 2026-02-21 10:02 ` Tao Tang
2026-02-25 20:27 ` Pierrick Bouvier
2026-02-21 10:02 ` [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events Tao Tang
` (25 subsequent siblings)
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:02 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Extend the register and queue helper routines to accept an explicit
SEC_SID argument instead of hard-coding the non-secure bank.
All existing callers are updated to pass SMMU_SEC_SID_NS, so the
behavior remains identical. This prepares the code for handling
additional security state banks in the future. So Non-secure state
is the only state bank supported for now.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Link: https://lore.kernel.org/qemu-devel/3097d58e-3793-4434-8beb-2e4f4c52f772@redhat.com/
---
hw/arm/smmuv3-accel.c | 3 ++-
hw/arm/smmuv3-internal.h | 21 +++++++++------------
hw/arm/smmuv3.c | 15 ++++++++-------
3 files changed, 19 insertions(+), 20 deletions(-)
diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
index 30d4b38c0a3..fdcb15005ea 100644
--- a/hw/arm/smmuv3-accel.c
+++ b/hw/arm/smmuv3-accel.c
@@ -243,6 +243,7 @@ bool smmuv3_accel_install_ste(SMMUv3State *s, SMMUDevice *sdev, int sid,
SMMUS1Hwpt *s1_hwpt = NULL;
const char *type;
STE ste;
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
if (!accel || !accel->viommu) {
return true;
@@ -272,7 +273,7 @@ bool smmuv3_accel_install_ste(SMMUv3State *s, SMMUDevice *sdev, int sid,
* attach/alloc fails, since the Guest–Host SID mapping stays
* valid as long as the device is behind the accelerated SMMUv3.
*/
- if (!smmu_enabled(s)) {
+ if (!smmu_enabled(s, sec_sid)) {
hwpt_id = smmuv3_accel_gbpa_hwpt(s, accel);
} else {
config = STE_CONFIG(&ste);
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index deb1ef60e87..866d62257e3 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -39,9 +39,8 @@ typedef enum SMMUTranslationClass {
SMMU_CLASS_IN,
} SMMUTranslationClass;
-static inline int smmu_enabled(SMMUv3State *s)
+static inline int smmu_enabled(SMMUv3State *s, SMMUSecSID sec_sid)
{
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
return FIELD_EX32(bank->cr[0], CR0, SMMUEN);
}
@@ -69,16 +68,16 @@ static inline uint32_t smmuv3_idreg(int regoffset)
return smmuv3_ids[regoffset / 4];
}
-static inline bool smmuv3_eventq_irq_enabled(SMMUv3State *s)
+static inline bool smmuv3_eventq_irq_enabled(SMMUv3State *s,
+ SMMUSecSID sec_sid)
{
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
return FIELD_EX32(bank->irq_ctrl, IRQ_CTRL, EVENTQ_IRQEN);
}
-static inline bool smmuv3_gerror_irq_enabled(SMMUv3State *s)
+static inline bool smmuv3_gerror_irq_enabled(SMMUv3State *s,
+ SMMUSecSID sec_sid)
{
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
return FIELD_EX32(bank->irq_ctrl, IRQ_CTRL, GERROR_IRQEN);
}
@@ -123,23 +122,21 @@ static inline void queue_cons_incr(SMMUQueue *q)
q->cons = deposit32(q->cons, 0, q->log2size + 1, q->cons + 1);
}
-static inline bool smmuv3_cmdq_enabled(SMMUv3State *s)
+static inline bool smmuv3_cmdq_enabled(SMMUv3State *s, SMMUSecSID sec_sid)
{
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
return FIELD_EX32(bank->cr[0], CR0, CMDQEN);
}
-static inline bool smmuv3_eventq_enabled(SMMUv3State *s)
+static inline bool smmuv3_eventq_enabled(SMMUv3State *s, SMMUSecSID sec_sid)
{
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
return FIELD_EX32(bank->cr[0], CR0, EVENTQEN);
}
-static inline void smmu_write_cmdq_err(SMMUv3State *s, uint32_t err_type)
+static inline void smmu_write_cmdq_err(SMMUv3State *s, uint32_t err_type,
+ SMMUSecSID sec_sid)
{
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
bank->cmdq.cons = FIELD_DP32(bank->cmdq.cons, CMDQ_CONS, ERR, err_type);
}
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 5511585601d..2c107724e77 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -59,7 +59,7 @@ static void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq,
switch (irq) {
case SMMU_IRQ_EVTQ:
- pulse = smmuv3_eventq_irq_enabled(s);
+ pulse = smmuv3_eventq_irq_enabled(s, sec_sid);
break;
case SMMU_IRQ_PRIQ:
qemu_log_mask(LOG_UNIMP, "PRI not yet supported\n");
@@ -79,7 +79,7 @@ static void smmuv3_trigger_irq(SMMUv3State *s, SMMUIrq irq,
bank->gerror ^= new_gerrors;
trace_smmuv3_write_gerror(new_gerrors, bank->gerror);
- pulse = smmuv3_gerror_irq_enabled(s);
+ pulse = smmuv3_gerror_irq_enabled(s, sec_sid);
break;
}
}
@@ -155,7 +155,7 @@ static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
SMMUQueue *q = &bank->eventq;
MemTxResult r;
- if (!smmuv3_eventq_enabled(s)) {
+ if (!smmuv3_eventq_enabled(s, sec_sid)) {
return MEMTX_ERROR;
}
@@ -178,8 +178,9 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
{
Evt evt = {};
MemTxResult r;
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
- if (!smmuv3_eventq_enabled(s)) {
+ if (!smmuv3_eventq_enabled(s, sec_sid)) {
return;
}
@@ -1087,7 +1088,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
qemu_mutex_lock(&s->mutex);
- if (!smmu_enabled(s)) {
+ if (!smmu_enabled(s, sec_sid)) {
if (FIELD_EX32(bank->gbpa, GBPA, ABORT)) {
status = SMMU_TRANS_ABORT;
} else {
@@ -1317,7 +1318,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
SMMUQueue *q = &bank->cmdq;
SMMUCommandType type = 0;
- if (!smmuv3_cmdq_enabled(s)) {
+ if (!smmuv3_cmdq_enabled(s, sec_sid)) {
return 0;
}
/*
@@ -1568,7 +1569,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
if (cmd_error) {
trace_smmuv3_cmdq_consume_error(smmu_cmd_string(type), cmd_error);
- smmu_write_cmdq_err(s, cmd_error);
+ smmu_write_cmdq_err(s, cmd_error, sec_sid);
smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_CMDQ_ERR_MASK);
}
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 05/31] hw/arm/smmuv3: Thread SEC_SID through helper APIs
2026-02-21 10:02 ` [RFC v4 05/31] hw/arm/smmuv3: Thread SEC_SID through helper APIs Tao Tang
@ 2026-02-25 20:27 ` Pierrick Bouvier
0 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 20:27 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:02 AM, Tao Tang wrote:
> Extend the register and queue helper routines to accept an explicit
> SEC_SID argument instead of hard-coding the non-secure bank.
>
> All existing callers are updated to pass SMMU_SEC_SID_NS, so the
> behavior remains identical. This prepares the code for handling
> additional security state banks in the future. So Non-secure state
> is the only state bank supported for now.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Link: https://lore.kernel.org/qemu-devel/3097d58e-3793-4434-8beb-2e4f4c52f772@redhat.com/
> ---
> hw/arm/smmuv3-accel.c | 3 ++-
> hw/arm/smmuv3-internal.h | 21 +++++++++------------
> hw/arm/smmuv3.c | 15 ++++++++-------
> 3 files changed, 19 insertions(+), 20 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (4 preceding siblings ...)
2026-02-21 10:02 ` [RFC v4 05/31] hw/arm/smmuv3: Thread SEC_SID through helper APIs Tao Tang
@ 2026-02-21 10:02 ` Tao Tang
2026-02-25 20:29 ` Pierrick Bouvier
` (2 more replies)
2026-02-21 10:02 ` [RFC v4 07/31] hw/arm/smmu-common: Add security-aware address space selector Tao Tang
` (24 subsequent siblings)
30 siblings, 3 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:02 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Cache the SEC_SID inside SMMUTransCfg to keep configuration lookups
tied to the correct register bank.
Plumb the SEC_SID through tracepoints and queue helpers so diagnostics
and event logs always show which security interface emitted the record.
To support this, the SEC_SID is placed in SMMUEventInfo so the bank is
identified as soon as an event record is built.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
hw/arm/smmuv3-internal.h | 1 +
hw/arm/smmuv3.c | 20 +++++++++++++-------
hw/arm/trace-events | 2 +-
include/hw/arm/smmu-common.h | 1 +
4 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index 866d62257e3..a1071f7b689 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -274,6 +274,7 @@ static inline const char *smmu_event_string(SMMUEventType type)
/* Encode an event record */
typedef struct SMMUEventInfo {
+ SMMUSecSID sec_sid;
SMMUEventType type;
uint32_t sid;
bool recorded;
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 2c107724e77..3438adcecd2 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -148,9 +148,9 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
return MEMTX_OK;
}
-static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
+static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
+ Evt *evt)
{
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
SMMUQueue *q = &bank->eventq;
MemTxResult r;
@@ -178,7 +178,8 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
{
Evt evt = {};
MemTxResult r;
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUSecSID sec_sid = info->sec_sid;
+ g_assert(sec_sid < SMMU_SEC_SID_NUM);
if (!smmuv3_eventq_enabled(s, sec_sid)) {
return;
@@ -258,8 +259,9 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
g_assert_not_reached();
}
- trace_smmuv3_record_event(smmu_event_string(info->type), info->sid);
- r = smmuv3_write_eventq(s, &evt);
+ trace_smmuv3_record_event(sec_sid, smmu_event_string(info->type),
+ info->sid);
+ r = smmuv3_write_eventq(s, sec_sid, &evt);
if (r != MEMTX_OK) {
smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_EVENTQ_ABT_ERR_MASK);
}
@@ -917,6 +919,7 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
100 * sdev->cfg_cache_hits /
(sdev->cfg_cache_hits + sdev->cfg_cache_misses));
cfg = g_new0(SMMUTransCfg, 1);
+ cfg->sec_sid = SMMU_SEC_SID_NS;
if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
g_hash_table_insert(bc->configs, sdev, cfg);
@@ -1074,7 +1077,8 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
SMMUEventInfo event = {.type = SMMU_EVT_NONE,
.sid = sid,
- .inval_ste_allowed = false};
+ .inval_ste_allowed = false,
+ .sec_sid = sec_sid};
SMMUTranslationStatus status;
SMMUTransCfg *cfg = NULL;
IOMMUTLBEntry entry = {
@@ -1176,7 +1180,9 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
uint64_t num_pages, int stage)
{
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
- SMMUEventInfo eventinfo = {.inval_ste_allowed = true};
+ SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
+ .inval_ste_allowed = true};
SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo);
IOMMUTLBEvent event;
uint8_t granule;
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index 8135c0c7344..9c2cc131ab4 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -40,7 +40,7 @@ smmuv3_cmdq_opcode(const char *opcode) "<--- %s"
smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d "
smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error on %s command execution: %d"
smmuv3_write_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"
-smmuv3_record_event(const char *type, uint32_t sid) "%s sid=0x%x"
+smmuv3_record_event(int sec_sid, const char *type, uint32_t sid) "sec_sid=%d %s sid=0x%x"
smmuv3_find_ste(uint16_t sid, uint32_t features, uint16_t sid_split) "sid=0x%x features:0x%x, sid_split:0x%x"
smmuv3_find_ste_2lvl(uint64_t strtab_base, uint64_t l1ptr, int l1_ste_offset, uint64_t l2ptr, int l2_ste_offset, int max_l2_ste) "strtab_base:0x%"PRIx64" l1ptr:0x%"PRIx64" l1_off:0x%x, l2ptr:0x%"PRIx64" l2_off:0x%x max_l2_ste:%d"
smmuv3_get_ste(uint64_t addr) "STE addr: 0x%"PRIx64
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index 6ea40f6b074..ae1489717fe 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -107,6 +107,7 @@ typedef struct SMMUS2Cfg {
typedef struct SMMUTransCfg {
/* Shared fields between stage-1 and stage-2. */
SMMUStage stage; /* translation stage */
+ SMMUSecSID sec_sid; /* cached sec sid */
bool disabled; /* smmu is disabled */
bool bypassed; /* translation is bypassed */
bool aborted; /* translation is aborted */
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events
2026-02-21 10:02 ` [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events Tao Tang
@ 2026-02-25 20:29 ` Pierrick Bouvier
2026-02-27 14:39 ` Mostafa Saleh
2026-03-02 16:13 ` Eric Auger
2 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 20:29 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:02 AM, Tao Tang wrote:
> Cache the SEC_SID inside SMMUTransCfg to keep configuration lookups
> tied to the correct register bank.
>
> Plumb the SEC_SID through tracepoints and queue helpers so diagnostics
> and event logs always show which security interface emitted the record.
> To support this, the SEC_SID is placed in SMMUEventInfo so the bank is
> identified as soon as an event record is built.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> ---
> hw/arm/smmuv3-internal.h | 1 +
> hw/arm/smmuv3.c | 20 +++++++++++++-------
> hw/arm/trace-events | 2 +-
> include/hw/arm/smmu-common.h | 1 +
> 4 files changed, 16 insertions(+), 8 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events
2026-02-21 10:02 ` [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events Tao Tang
2026-02-25 20:29 ` Pierrick Bouvier
@ 2026-02-27 14:39 ` Mostafa Saleh
2026-03-01 13:53 ` Tao Tang
2026-03-02 16:13 ` Eric Auger
2 siblings, 1 reply; 136+ messages in thread
From: Mostafa Saleh @ 2026-02-27 14:39 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sat, Feb 21, 2026 at 06:02:25PM +0800, Tao Tang wrote:
> Cache the SEC_SID inside SMMUTransCfg to keep configuration lookups
> tied to the correct register bank.
>
> Plumb the SEC_SID through tracepoints and queue helpers so diagnostics
> and event logs always show which security interface emitted the record.
> To support this, the SEC_SID is placed in SMMUEventInfo so the bank is
> identified as soon as an event record is built.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> ---
> hw/arm/smmuv3-internal.h | 1 +
> hw/arm/smmuv3.c | 20 +++++++++++++-------
> hw/arm/trace-events | 2 +-
> include/hw/arm/smmu-common.h | 1 +
> 4 files changed, 16 insertions(+), 8 deletions(-)
>
> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> index 866d62257e3..a1071f7b689 100644
> --- a/hw/arm/smmuv3-internal.h
> +++ b/hw/arm/smmuv3-internal.h
> @@ -274,6 +274,7 @@ static inline const char *smmu_event_string(SMMUEventType type)
>
> /* Encode an event record */
> typedef struct SMMUEventInfo {
> + SMMUSecSID sec_sid;
> SMMUEventType type;
> uint32_t sid;
> bool recorded;
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 2c107724e77..3438adcecd2 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -148,9 +148,9 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
> return MEMTX_OK;
> }
>
> -static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
> +static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
> + Evt *evt)
> {
> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> SMMUQueue *q = &bank->eventq;
> MemTxResult r;
> @@ -178,7 +178,8 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
> {
> Evt evt = {};
> MemTxResult r;
> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUSecSID sec_sid = info->sec_sid;
> + g_assert(sec_sid < SMMU_SEC_SID_NUM);
What does this defend against?
Thanks,
Mostafa
>
> if (!smmuv3_eventq_enabled(s, sec_sid)) {
> return;
> @@ -258,8 +259,9 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
> g_assert_not_reached();
> }
>
> - trace_smmuv3_record_event(smmu_event_string(info->type), info->sid);
> - r = smmuv3_write_eventq(s, &evt);
> + trace_smmuv3_record_event(sec_sid, smmu_event_string(info->type),
> + info->sid);
> + r = smmuv3_write_eventq(s, sec_sid, &evt);
> if (r != MEMTX_OK) {
> smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_EVENTQ_ABT_ERR_MASK);
> }
> @@ -917,6 +919,7 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
> 100 * sdev->cfg_cache_hits /
> (sdev->cfg_cache_hits + sdev->cfg_cache_misses));
> cfg = g_new0(SMMUTransCfg, 1);
> + cfg->sec_sid = SMMU_SEC_SID_NS;
>
> if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
> g_hash_table_insert(bc->configs, sdev, cfg);
> @@ -1074,7 +1077,8 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> SMMUEventInfo event = {.type = SMMU_EVT_NONE,
> .sid = sid,
> - .inval_ste_allowed = false};
> + .inval_ste_allowed = false,
> + .sec_sid = sec_sid};
> SMMUTranslationStatus status;
> SMMUTransCfg *cfg = NULL;
> IOMMUTLBEntry entry = {
> @@ -1176,7 +1180,9 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> uint64_t num_pages, int stage)
> {
> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
> - SMMUEventInfo eventinfo = {.inval_ste_allowed = true};
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
> + .inval_ste_allowed = true};
> SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo);
> IOMMUTLBEvent event;
> uint8_t granule;
> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> index 8135c0c7344..9c2cc131ab4 100644
> --- a/hw/arm/trace-events
> +++ b/hw/arm/trace-events
> @@ -40,7 +40,7 @@ smmuv3_cmdq_opcode(const char *opcode) "<--- %s"
> smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d "
> smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error on %s command execution: %d"
> smmuv3_write_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"
> -smmuv3_record_event(const char *type, uint32_t sid) "%s sid=0x%x"
> +smmuv3_record_event(int sec_sid, const char *type, uint32_t sid) "sec_sid=%d %s sid=0x%x"
> smmuv3_find_ste(uint16_t sid, uint32_t features, uint16_t sid_split) "sid=0x%x features:0x%x, sid_split:0x%x"
> smmuv3_find_ste_2lvl(uint64_t strtab_base, uint64_t l1ptr, int l1_ste_offset, uint64_t l2ptr, int l2_ste_offset, int max_l2_ste) "strtab_base:0x%"PRIx64" l1ptr:0x%"PRIx64" l1_off:0x%x, l2ptr:0x%"PRIx64" l2_off:0x%x max_l2_ste:%d"
> smmuv3_get_ste(uint64_t addr) "STE addr: 0x%"PRIx64
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index 6ea40f6b074..ae1489717fe 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -107,6 +107,7 @@ typedef struct SMMUS2Cfg {
> typedef struct SMMUTransCfg {
> /* Shared fields between stage-1 and stage-2. */
> SMMUStage stage; /* translation stage */
> + SMMUSecSID sec_sid; /* cached sec sid */
> bool disabled; /* smmu is disabled */
> bool bypassed; /* translation is bypassed */
> bool aborted; /* translation is aborted */
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events
2026-02-27 14:39 ` Mostafa Saleh
@ 2026-03-01 13:53 ` Tao Tang
2026-03-02 10:19 ` Mostafa Saleh
0 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-03-01 13:53 UTC (permalink / raw)
To: Mostafa Saleh
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
Hi Mostafa,
On 2026/2/27 PM10:39, Mostafa Saleh wrote:
> On Sat, Feb 21, 2026 at 06:02:25PM +0800, Tao Tang wrote:
>> Cache the SEC_SID inside SMMUTransCfg to keep configuration lookups
>> tied to the correct register bank.
>>
>> Plumb the SEC_SID through tracepoints and queue helpers so diagnostics
>> and event logs always show which security interface emitted the record.
>> To support this, the SEC_SID is placed in SMMUEventInfo so the bank is
>> identified as soon as an event record is built.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> ---
>> hw/arm/smmuv3-internal.h | 1 +
>> hw/arm/smmuv3.c | 20 +++++++++++++-------
>> hw/arm/trace-events | 2 +-
>> include/hw/arm/smmu-common.h | 1 +
>> 4 files changed, 16 insertions(+), 8 deletions(-)
>>
>> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
>> index 866d62257e3..a1071f7b689 100644
>> --- a/hw/arm/smmuv3-internal.h
>> +++ b/hw/arm/smmuv3-internal.h
>> @@ -274,6 +274,7 @@ static inline const char *smmu_event_string(SMMUEventType type)
>>
>> /* Encode an event record */
>> typedef struct SMMUEventInfo {
>> + SMMUSecSID sec_sid;
>> SMMUEventType type;
>> uint32_t sid;
>> bool recorded;
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index 2c107724e77..3438adcecd2 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -148,9 +148,9 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
>> return MEMTX_OK;
>> }
>>
>> -static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
>> +static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
>> + Evt *evt)
>> {
>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>> SMMUQueue *q = &bank->eventq;
>> MemTxResult r;
>> @@ -178,7 +178,8 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
>> {
>> Evt evt = {};
>> MemTxResult r;
>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> + SMMUSecSID sec_sid = info->sec_sid;
>> + g_assert(sec_sid < SMMU_SEC_SID_NUM);
> What does this defend against?
sec_sid is now taken from SMMUEventInfo, so the assert is to catch
programming errors early and avoid out-of-bounds bank accesses in
smmuv3_record_event.
>
> Thanks,
> Mostafa
Best regards,
Tao
>
>>
>> if (!smmuv3_eventq_enabled(s, sec_sid)) {
>> return;
>> @@ -258,8 +259,9 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
>> g_assert_not_reached();
>> }
>>
>> - trace_smmuv3_record_event(smmu_event_string(info->type), info->sid);
>> - r = smmuv3_write_eventq(s, &evt);
>> + trace_smmuv3_record_event(sec_sid, smmu_event_string(info->type),
>> + info->sid);
>> + r = smmuv3_write_eventq(s, sec_sid, &evt);
>> if (r != MEMTX_OK) {
>> smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_EVENTQ_ABT_ERR_MASK);
>> }
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events
2026-03-01 13:53 ` Tao Tang
@ 2026-03-02 10:19 ` Mostafa Saleh
2026-03-02 13:45 ` Eric Auger
0 siblings, 1 reply; 136+ messages in thread
From: Mostafa Saleh @ 2026-03-02 10:19 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sun, Mar 01, 2026 at 09:53:24PM +0800, Tao Tang wrote:
> Hi Mostafa,
>
> On 2026/2/27 PM10:39, Mostafa Saleh wrote:
> > On Sat, Feb 21, 2026 at 06:02:25PM +0800, Tao Tang wrote:
> > > Cache the SEC_SID inside SMMUTransCfg to keep configuration lookups
> > > tied to the correct register bank.
> > >
> > > Plumb the SEC_SID through tracepoints and queue helpers so diagnostics
> > > and event logs always show which security interface emitted the record.
> > > To support this, the SEC_SID is placed in SMMUEventInfo so the bank is
> > > identified as soon as an event record is built.
> > >
> > > Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> > > Reviewed-by: Eric Auger <eric.auger@redhat.com>
> > > ---
> > > hw/arm/smmuv3-internal.h | 1 +
> > > hw/arm/smmuv3.c | 20 +++++++++++++-------
> > > hw/arm/trace-events | 2 +-
> > > include/hw/arm/smmu-common.h | 1 +
> > > 4 files changed, 16 insertions(+), 8 deletions(-)
> > >
> > > diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> > > index 866d62257e3..a1071f7b689 100644
> > > --- a/hw/arm/smmuv3-internal.h
> > > +++ b/hw/arm/smmuv3-internal.h
> > > @@ -274,6 +274,7 @@ static inline const char *smmu_event_string(SMMUEventType type)
> > > /* Encode an event record */
> > > typedef struct SMMUEventInfo {
> > > + SMMUSecSID sec_sid;
> > > SMMUEventType type;
> > > uint32_t sid;
> > > bool recorded;
> > > diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> > > index 2c107724e77..3438adcecd2 100644
> > > --- a/hw/arm/smmuv3.c
> > > +++ b/hw/arm/smmuv3.c
> > > @@ -148,9 +148,9 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
> > > return MEMTX_OK;
> > > }
> > > -static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
> > > +static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
> > > + Evt *evt)
> > > {
> > > - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> > > SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> > > SMMUQueue *q = &bank->eventq;
> > > MemTxResult r;
> > > @@ -178,7 +178,8 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
> > > {
> > > Evt evt = {};
> > > MemTxResult r;
> > > - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> > > + SMMUSecSID sec_sid = info->sec_sid;
> > > + g_assert(sec_sid < SMMU_SEC_SID_NUM);
> > What does this defend against?
>
>
> sec_sid is now taken from SMMUEventInfo, so the assert is to catch
> programming errors early and avoid out-of-bounds bank accesses in
> smmuv3_record_event.
Personally, I don't like this kind of defensive programming, someone can
argue we can add such checks anywhere.
I believe we should definitely know the possible states in the software
and add checks needed at guest inputs.
But that's also up to Eric.
Thanks,
Mostafa
>
> >
> > Thanks,
> > Mostafa
>
>
> Best regards,
>
> Tao
>
> >
> > > if (!smmuv3_eventq_enabled(s, sec_sid)) {
> > > return;
> > > @@ -258,8 +259,9 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
> > > g_assert_not_reached();
> > > }
> > > - trace_smmuv3_record_event(smmu_event_string(info->type), info->sid);
> > > - r = smmuv3_write_eventq(s, &evt);
> > > + trace_smmuv3_record_event(sec_sid, smmu_event_string(info->type),
> > > + info->sid);
> > > + r = smmuv3_write_eventq(s, sec_sid, &evt);
> > > if (r != MEMTX_OK) {
> > > smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_EVENTQ_ABT_ERR_MASK);
> > > }
>
>
>
>
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events
2026-03-02 10:19 ` Mostafa Saleh
@ 2026-03-02 13:45 ` Eric Auger
0 siblings, 0 replies; 136+ messages in thread
From: Eric Auger @ 2026-03-02 13:45 UTC (permalink / raw)
To: Mostafa Saleh, Tao Tang
Cc: Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum, qemu-devel,
qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
Hi Tao,
On 3/2/26 11:19 AM, Mostafa Saleh wrote:
> On Sun, Mar 01, 2026 at 09:53:24PM +0800, Tao Tang wrote:
>> Hi Mostafa,
>>
>> On 2026/2/27 PM10:39, Mostafa Saleh wrote:
>>> On Sat, Feb 21, 2026 at 06:02:25PM +0800, Tao Tang wrote:
>>>> Cache the SEC_SID inside SMMUTransCfg to keep configuration lookups
>>>> tied to the correct register bank.
>>>>
>>>> Plumb the SEC_SID through tracepoints and queue helpers so diagnostics
>>>> and event logs always show which security interface emitted the record.
>>>> To support this, the SEC_SID is placed in SMMUEventInfo so the bank is
>>>> identified as soon as an event record is built.
>>>>
>>>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>>>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>>>> ---
>>>> hw/arm/smmuv3-internal.h | 1 +
>>>> hw/arm/smmuv3.c | 20 +++++++++++++-------
>>>> hw/arm/trace-events | 2 +-
>>>> include/hw/arm/smmu-common.h | 1 +
>>>> 4 files changed, 16 insertions(+), 8 deletions(-)
>>>>
>>>> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
>>>> index 866d62257e3..a1071f7b689 100644
>>>> --- a/hw/arm/smmuv3-internal.h
>>>> +++ b/hw/arm/smmuv3-internal.h
>>>> @@ -274,6 +274,7 @@ static inline const char *smmu_event_string(SMMUEventType type)
>>>> /* Encode an event record */
>>>> typedef struct SMMUEventInfo {
>>>> + SMMUSecSID sec_sid;
>>>> SMMUEventType type;
>>>> uint32_t sid;
>>>> bool recorded;
>>>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>>>> index 2c107724e77..3438adcecd2 100644
>>>> --- a/hw/arm/smmuv3.c
>>>> +++ b/hw/arm/smmuv3.c
>>>> @@ -148,9 +148,9 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
>>>> return MEMTX_OK;
>>>> }
>>>> -static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
>>>> +static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
>>>> + Evt *evt)
>>>> {
>>>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>>>> SMMUQueue *q = &bank->eventq;
>>>> MemTxResult r;
>>>> @@ -178,7 +178,8 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
>>>> {
>>>> Evt evt = {};
>>>> MemTxResult r;
>>>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>>> + SMMUSecSID sec_sid = info->sec_sid;
>>>> + g_assert(sec_sid < SMMU_SEC_SID_NUM);
>>> What does this defend against?
>>
>> sec_sid is now taken from SMMUEventInfo, so the assert is to catch
>> programming errors early and avoid out-of-bounds bank accesses in
>> smmuv3_record_event.
> Personally, I don't like this kind of defensive programming, someone can
> argue we can add such checks anywhere.
> I believe we should definitely know the possible states in the software
> and add checks needed at guest inputs.
> But that's also up to Eric.
I tend to agree with Mostafa. We shall avoid putting those asserts
everywhere. Would it make sense to pove it to smmuv3_bank directly?
Eric
>
> Thanks,
> Mostafa
>
>>> Thanks,
>>> Mostafa
>>
>> Best regards,
>>
>> Tao
>>
>>>> if (!smmuv3_eventq_enabled(s, sec_sid)) {
>>>> return;
>>>> @@ -258,8 +259,9 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
>>>> g_assert_not_reached();
>>>> }
>>>> - trace_smmuv3_record_event(smmu_event_string(info->type), info->sid);
>>>> - r = smmuv3_write_eventq(s, &evt);
>>>> + trace_smmuv3_record_event(sec_sid, smmu_event_string(info->type),
>>>> + info->sid);
>>>> + r = smmuv3_write_eventq(s, sec_sid, &evt);
>>>> if (r != MEMTX_OK) {
>>>> smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_EVENTQ_ABT_ERR_MASK);
>>>> }
>>
>>
>>
>>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events
2026-02-21 10:02 ` [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events Tao Tang
2026-02-25 20:29 ` Pierrick Bouvier
2026-02-27 14:39 ` Mostafa Saleh
@ 2026-03-02 16:13 ` Eric Auger
2026-03-03 7:26 ` Eric Auger via qemu development
2 siblings, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-02 16:13 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi Tao,
On 2/21/26 11:02 AM, Tao Tang wrote:
> Cache the SEC_SID inside SMMUTransCfg to keep configuration lookups
> tied to the correct register bank.
>
> Plumb the SEC_SID through tracepoints and queue helpers so diagnostics
> and event logs always show which security interface emitted the record.
> To support this, the SEC_SID is placed in SMMUEventInfo so the bank is
> identified as soon as an event record is built.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> ---
> hw/arm/smmuv3-internal.h | 1 +
> hw/arm/smmuv3.c | 20 +++++++++++++-------
> hw/arm/trace-events | 2 +-
> include/hw/arm/smmu-common.h | 1 +
> 4 files changed, 16 insertions(+), 8 deletions(-)
>
> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> index 866d62257e3..a1071f7b689 100644
> --- a/hw/arm/smmuv3-internal.h
> +++ b/hw/arm/smmuv3-internal.h
> @@ -274,6 +274,7 @@ static inline const char *smmu_event_string(SMMUEventType type)
>
> /* Encode an event record */
> typedef struct SMMUEventInfo {
> + SMMUSecSID sec_sid;
> SMMUEventType type;
> uint32_t sid;
> bool recorded;
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 2c107724e77..3438adcecd2 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -148,9 +148,9 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
> return MEMTX_OK;
> }
>
> -static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
> +static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
> + Evt *evt)
> {
> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> SMMUQueue *q = &bank->eventq;
> MemTxResult r;
> @@ -178,7 +178,8 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
> {
> Evt evt = {};
> MemTxResult r;
> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUSecSID sec_sid = info->sec_sid;
> + g_assert(sec_sid < SMMU_SEC_SID_NUM);
>
> if (!smmuv3_eventq_enabled(s, sec_sid)) {
> return;
> @@ -258,8 +259,9 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
> g_assert_not_reached();
> }
>
> - trace_smmuv3_record_event(smmu_event_string(info->type), info->sid);
> - r = smmuv3_write_eventq(s, &evt);
> + trace_smmuv3_record_event(sec_sid, smmu_event_string(info->type),
> + info->sid);
> + r = smmuv3_write_eventq(s, sec_sid, &evt);
> if (r != MEMTX_OK) {
> smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_EVENTQ_ABT_ERR_MASK);
> }
> @@ -917,6 +919,7 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
> 100 * sdev->cfg_cache_hits /
> (sdev->cfg_cache_hits + sdev->cfg_cache_misses));
> cfg = g_new0(SMMUTransCfg, 1);
> + cfg->sec_sid = SMMU_SEC_SID_NS;
>
> if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
> g_hash_table_insert(bc->configs, sdev, cfg);
> @@ -1074,7 +1077,8 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> SMMUEventInfo event = {.type = SMMU_EVT_NONE,
> .sid = sid,
> - .inval_ste_allowed = false};
> + .inval_ste_allowed = false,
> + .sec_sid = sec_sid};
> SMMUTranslationStatus status;
> SMMUTransCfg *cfg = NULL;
> IOMMUTLBEntry entry = {
> @@ -1176,7 +1180,9 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> uint64_t num_pages, int stage)
> {
> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
> - SMMUEventInfo eventinfo = {.inval_ste_allowed = true};
> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
> + .inval_ste_allowed = true};
> SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo);
> IOMMUTLBEvent event;
> uint8_t granule;
> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> index 8135c0c7344..9c2cc131ab4 100644
> --- a/hw/arm/trace-events
> +++ b/hw/arm/trace-events
> @@ -40,7 +40,7 @@ smmuv3_cmdq_opcode(const char *opcode) "<--- %s"
> smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d "
> smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error on %s command execution: %d"
> smmuv3_write_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"
> -smmuv3_record_event(const char *type, uint32_t sid) "%s sid=0x%x"
> +smmuv3_record_event(int sec_sid, const char *type, uint32_t sid) "sec_sid=%d %s sid=0x%x"
> smmuv3_find_ste(uint16_t sid, uint32_t features, uint16_t sid_split) "sid=0x%x features:0x%x, sid_split:0x%x"
> smmuv3_find_ste_2lvl(uint64_t strtab_base, uint64_t l1ptr, int l1_ste_offset, uint64_t l2ptr, int l2_ste_offset, int max_l2_ste) "strtab_base:0x%"PRIx64" l1ptr:0x%"PRIx64" l1_off:0x%x, l2ptr:0x%"PRIx64" l2_off:0x%x max_l2_ste:%d"
> smmuv3_get_ste(uint64_t addr) "STE addr: 0x%"PRIx64
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index 6ea40f6b074..ae1489717fe 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -107,6 +107,7 @@ typedef struct SMMUS2Cfg {
> typedef struct SMMUTransCfg {
> /* Shared fields between stage-1 and stage-2. */
> SMMUStage stage; /* translation stage */
> + SMMUSecSID sec_sid; /* cached sec sid */
I am now wondering if sec_sid shall be part of the TransCfg as this is
never decoded from STE/CD, sin't it.
Eric
> bool disabled; /* smmu is disabled */
> bool bypassed; /* translation is bypassed */
> bool aborted; /* translation is aborted */
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events
2026-03-02 16:13 ` Eric Auger
@ 2026-03-03 7:26 ` Eric Auger via qemu development
0 siblings, 0 replies; 136+ messages in thread
From: Eric Auger via @ 2026-03-03 7:26 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 3/2/26 5:13 PM, Eric Auger wrote:
> Hi Tao,
>
> On 2/21/26 11:02 AM, Tao Tang wrote:
>> Cache the SEC_SID inside SMMUTransCfg to keep configuration lookups
>> tied to the correct register bank.
>>
>> Plumb the SEC_SID through tracepoints and queue helpers so diagnostics
>> and event logs always show which security interface emitted the record.
>> To support this, the SEC_SID is placed in SMMUEventInfo so the bank is
>> identified as soon as an event record is built.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> ---
>> hw/arm/smmuv3-internal.h | 1 +
>> hw/arm/smmuv3.c | 20 +++++++++++++-------
>> hw/arm/trace-events | 2 +-
>> include/hw/arm/smmu-common.h | 1 +
>> 4 files changed, 16 insertions(+), 8 deletions(-)
>>
>> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
>> index 866d62257e3..a1071f7b689 100644
>> --- a/hw/arm/smmuv3-internal.h
>> +++ b/hw/arm/smmuv3-internal.h
>> @@ -274,6 +274,7 @@ static inline const char *smmu_event_string(SMMUEventType type)
>>
>> /* Encode an event record */
>> typedef struct SMMUEventInfo {
>> + SMMUSecSID sec_sid;
>> SMMUEventType type;
>> uint32_t sid;
>> bool recorded;
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index 2c107724e77..3438adcecd2 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -148,9 +148,9 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
>> return MEMTX_OK;
>> }
>>
>> -static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
>> +static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
>> + Evt *evt)
>> {
>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>> SMMUQueue *q = &bank->eventq;
>> MemTxResult r;
>> @@ -178,7 +178,8 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
>> {
>> Evt evt = {};
>> MemTxResult r;
>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> + SMMUSecSID sec_sid = info->sec_sid;
>> + g_assert(sec_sid < SMMU_SEC_SID_NUM);
>>
>> if (!smmuv3_eventq_enabled(s, sec_sid)) {
>> return;
>> @@ -258,8 +259,9 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
>> g_assert_not_reached();
>> }
>>
>> - trace_smmuv3_record_event(smmu_event_string(info->type), info->sid);
>> - r = smmuv3_write_eventq(s, &evt);
>> + trace_smmuv3_record_event(sec_sid, smmu_event_string(info->type),
>> + info->sid);
>> + r = smmuv3_write_eventq(s, sec_sid, &evt);
>> if (r != MEMTX_OK) {
>> smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_EVENTQ_ABT_ERR_MASK);
>> }
>> @@ -917,6 +919,7 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
>> 100 * sdev->cfg_cache_hits /
>> (sdev->cfg_cache_hits + sdev->cfg_cache_misses));
>> cfg = g_new0(SMMUTransCfg, 1);
>> + cfg->sec_sid = SMMU_SEC_SID_NS;
>>
>> if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
>> g_hash_table_insert(bc->configs, sdev, cfg);
>> @@ -1074,7 +1077,8 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>> SMMUEventInfo event = {.type = SMMU_EVT_NONE,
>> .sid = sid,
>> - .inval_ste_allowed = false};
>> + .inval_ste_allowed = false,
>> + .sec_sid = sec_sid};
>> SMMUTranslationStatus status;
>> SMMUTransCfg *cfg = NULL;
>> IOMMUTLBEntry entry = {
>> @@ -1176,7 +1180,9 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>> uint64_t num_pages, int stage)
>> {
>> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
>> - SMMUEventInfo eventinfo = {.inval_ste_allowed = true};
>> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> + SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
>> + .inval_ste_allowed = true};
>> SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo);
>> IOMMUTLBEvent event;
>> uint8_t granule;
>> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
>> index 8135c0c7344..9c2cc131ab4 100644
>> --- a/hw/arm/trace-events
>> +++ b/hw/arm/trace-events
>> @@ -40,7 +40,7 @@ smmuv3_cmdq_opcode(const char *opcode) "<--- %s"
>> smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d "
>> smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error on %s command execution: %d"
>> smmuv3_write_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"
>> -smmuv3_record_event(const char *type, uint32_t sid) "%s sid=0x%x"
>> +smmuv3_record_event(int sec_sid, const char *type, uint32_t sid) "sec_sid=%d %s sid=0x%x"
>> smmuv3_find_ste(uint16_t sid, uint32_t features, uint16_t sid_split) "sid=0x%x features:0x%x, sid_split:0x%x"
>> smmuv3_find_ste_2lvl(uint64_t strtab_base, uint64_t l1ptr, int l1_ste_offset, uint64_t l2ptr, int l2_ste_offset, int max_l2_ste) "strtab_base:0x%"PRIx64" l1ptr:0x%"PRIx64" l1_off:0x%x, l2ptr:0x%"PRIx64" l2_off:0x%x max_l2_ste:%d"
>> smmuv3_get_ste(uint64_t addr) "STE addr: 0x%"PRIx64
>> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
>> index 6ea40f6b074..ae1489717fe 100644
>> --- a/include/hw/arm/smmu-common.h
>> +++ b/include/hw/arm/smmu-common.h
>> @@ -107,6 +107,7 @@ typedef struct SMMUS2Cfg {
>> typedef struct SMMUTransCfg {
>> /* Shared fields between stage-1 and stage-2. */
>> SMMUStage stage; /* translation stage */
>> + SMMUSecSID sec_sid; /* cached sec sid */
> I am now wondering if sec_sid shall be part of the TransCfg as this is
> never decoded from STE/CD, sin't it.
Having slept over it, caching sed_id here indicates whether the secure
stream table was used for decoding. So that can be considered as a
result of the config decode process.
a minor comment though, I think I would prefer having cfg->sec_sid
populated in smmuv3_decode_config as the other cfg fields. Meaning I
would rather add sed_sid to smmuv3_decode_config signature.
Thanks
Eric
>
> Eric
>> bool disabled; /* smmu is disabled */
>> bool bypassed; /* translation is bypassed */
>> bool aborted; /* translation is aborted */
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events
@ 2026-03-03 7:26 ` Eric Auger via qemu development
0 siblings, 0 replies; 136+ messages in thread
From: Eric Auger via qemu development @ 2026-03-03 7:26 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 3/2/26 5:13 PM, Eric Auger wrote:
> Hi Tao,
>
> On 2/21/26 11:02 AM, Tao Tang wrote:
>> Cache the SEC_SID inside SMMUTransCfg to keep configuration lookups
>> tied to the correct register bank.
>>
>> Plumb the SEC_SID through tracepoints and queue helpers so diagnostics
>> and event logs always show which security interface emitted the record.
>> To support this, the SEC_SID is placed in SMMUEventInfo so the bank is
>> identified as soon as an event record is built.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> ---
>> hw/arm/smmuv3-internal.h | 1 +
>> hw/arm/smmuv3.c | 20 +++++++++++++-------
>> hw/arm/trace-events | 2 +-
>> include/hw/arm/smmu-common.h | 1 +
>> 4 files changed, 16 insertions(+), 8 deletions(-)
>>
>> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
>> index 866d62257e3..a1071f7b689 100644
>> --- a/hw/arm/smmuv3-internal.h
>> +++ b/hw/arm/smmuv3-internal.h
>> @@ -274,6 +274,7 @@ static inline const char *smmu_event_string(SMMUEventType type)
>>
>> /* Encode an event record */
>> typedef struct SMMUEventInfo {
>> + SMMUSecSID sec_sid;
>> SMMUEventType type;
>> uint32_t sid;
>> bool recorded;
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index 2c107724e77..3438adcecd2 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -148,9 +148,9 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
>> return MEMTX_OK;
>> }
>>
>> -static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
>> +static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
>> + Evt *evt)
>> {
>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>> SMMUQueue *q = &bank->eventq;
>> MemTxResult r;
>> @@ -178,7 +178,8 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
>> {
>> Evt evt = {};
>> MemTxResult r;
>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> + SMMUSecSID sec_sid = info->sec_sid;
>> + g_assert(sec_sid < SMMU_SEC_SID_NUM);
>>
>> if (!smmuv3_eventq_enabled(s, sec_sid)) {
>> return;
>> @@ -258,8 +259,9 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
>> g_assert_not_reached();
>> }
>>
>> - trace_smmuv3_record_event(smmu_event_string(info->type), info->sid);
>> - r = smmuv3_write_eventq(s, &evt);
>> + trace_smmuv3_record_event(sec_sid, smmu_event_string(info->type),
>> + info->sid);
>> + r = smmuv3_write_eventq(s, sec_sid, &evt);
>> if (r != MEMTX_OK) {
>> smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_EVENTQ_ABT_ERR_MASK);
>> }
>> @@ -917,6 +919,7 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
>> 100 * sdev->cfg_cache_hits /
>> (sdev->cfg_cache_hits + sdev->cfg_cache_misses));
>> cfg = g_new0(SMMUTransCfg, 1);
>> + cfg->sec_sid = SMMU_SEC_SID_NS;
>>
>> if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
>> g_hash_table_insert(bc->configs, sdev, cfg);
>> @@ -1074,7 +1077,8 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>> SMMUEventInfo event = {.type = SMMU_EVT_NONE,
>> .sid = sid,
>> - .inval_ste_allowed = false};
>> + .inval_ste_allowed = false,
>> + .sec_sid = sec_sid};
>> SMMUTranslationStatus status;
>> SMMUTransCfg *cfg = NULL;
>> IOMMUTLBEntry entry = {
>> @@ -1176,7 +1180,9 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>> uint64_t num_pages, int stage)
>> {
>> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
>> - SMMUEventInfo eventinfo = {.inval_ste_allowed = true};
>> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> + SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
>> + .inval_ste_allowed = true};
>> SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo);
>> IOMMUTLBEvent event;
>> uint8_t granule;
>> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
>> index 8135c0c7344..9c2cc131ab4 100644
>> --- a/hw/arm/trace-events
>> +++ b/hw/arm/trace-events
>> @@ -40,7 +40,7 @@ smmuv3_cmdq_opcode(const char *opcode) "<--- %s"
>> smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d "
>> smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error on %s command execution: %d"
>> smmuv3_write_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"
>> -smmuv3_record_event(const char *type, uint32_t sid) "%s sid=0x%x"
>> +smmuv3_record_event(int sec_sid, const char *type, uint32_t sid) "sec_sid=%d %s sid=0x%x"
>> smmuv3_find_ste(uint16_t sid, uint32_t features, uint16_t sid_split) "sid=0x%x features:0x%x, sid_split:0x%x"
>> smmuv3_find_ste_2lvl(uint64_t strtab_base, uint64_t l1ptr, int l1_ste_offset, uint64_t l2ptr, int l2_ste_offset, int max_l2_ste) "strtab_base:0x%"PRIx64" l1ptr:0x%"PRIx64" l1_off:0x%x, l2ptr:0x%"PRIx64" l2_off:0x%x max_l2_ste:%d"
>> smmuv3_get_ste(uint64_t addr) "STE addr: 0x%"PRIx64
>> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
>> index 6ea40f6b074..ae1489717fe 100644
>> --- a/include/hw/arm/smmu-common.h
>> +++ b/include/hw/arm/smmu-common.h
>> @@ -107,6 +107,7 @@ typedef struct SMMUS2Cfg {
>> typedef struct SMMUTransCfg {
>> /* Shared fields between stage-1 and stage-2. */
>> SMMUStage stage; /* translation stage */
>> + SMMUSecSID sec_sid; /* cached sec sid */
> I am now wondering if sec_sid shall be part of the TransCfg as this is
> never decoded from STE/CD, sin't it.
Having slept over it, caching sed_id here indicates whether the secure
stream table was used for decoding. So that can be considered as a
result of the config decode process.
a minor comment though, I think I would prefer having cfg->sec_sid
populated in smmuv3_decode_config as the other cfg fields. Meaning I
would rather add sed_sid to smmuv3_decode_config signature.
Thanks
Eric
>
> Eric
>> bool disabled; /* smmu is disabled */
>> bool bypassed; /* translation is bypassed */
>> bool aborted; /* translation is aborted */
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events
2026-03-03 7:26 ` Eric Auger via qemu development
(?)
@ 2026-03-06 13:56 ` Tao Tang
-1 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-06 13:56 UTC (permalink / raw)
To: eric.auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi all,
On 2026/3/3 15:26, Eric Auger wrote:
>
> On 3/2/26 5:13 PM, Eric Auger wrote:
>> Hi Tao,
>>
>> On 2/21/26 11:02 AM, Tao Tang wrote:
>>> Cache the SEC_SID inside SMMUTransCfg to keep configuration lookups
>>> tied to the correct register bank.
>>>
>>> Plumb the SEC_SID through tracepoints and queue helpers so diagnostics
>>> and event logs always show which security interface emitted the record.
>>> To support this, the SEC_SID is placed in SMMUEventInfo so the bank is
>>> identified as soon as an event record is built.
>>>
>>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>>> ---
>>> hw/arm/smmuv3-internal.h | 1 +
>>> hw/arm/smmuv3.c | 20 +++++++++++++-------
>>> hw/arm/trace-events | 2 +-
>>> include/hw/arm/smmu-common.h | 1 +
>>> 4 files changed, 16 insertions(+), 8 deletions(-)
>>>
>>> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
>>> index 866d62257e3..a1071f7b689 100644
>>> --- a/hw/arm/smmuv3-internal.h
>>> +++ b/hw/arm/smmuv3-internal.h
>>> @@ -274,6 +274,7 @@ static inline const char *smmu_event_string(SMMUEventType type)
>>>
>>> /* Encode an event record */
>>> typedef struct SMMUEventInfo {
>>> + SMMUSecSID sec_sid;
>>> SMMUEventType type;
>>> uint32_t sid;
>>> bool recorded;
>>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>>> index 2c107724e77..3438adcecd2 100644
>>> --- a/hw/arm/smmuv3.c
>>> +++ b/hw/arm/smmuv3.c
>>> @@ -148,9 +148,9 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
>>> return MEMTX_OK;
>>> }
>>>
>>> -static MemTxResult smmuv3_write_eventq(SMMUv3State *s, Evt *evt)
>>> +static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
>>> + Evt *evt)
>>> {
>>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>>> SMMUQueue *q = &bank->eventq;
>>> MemTxResult r;
>>> @@ -178,7 +178,8 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
>>> {
>>> Evt evt = {};
>>> MemTxResult r;
>>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>> + SMMUSecSID sec_sid = info->sec_sid;
>>> + g_assert(sec_sid < SMMU_SEC_SID_NUM);
>>>
>>> if (!smmuv3_eventq_enabled(s, sec_sid)) {
>>> return;
>>> @@ -258,8 +259,9 @@ void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *info)
>>> g_assert_not_reached();
>>> }
>>>
>>> - trace_smmuv3_record_event(smmu_event_string(info->type), info->sid);
>>> - r = smmuv3_write_eventq(s, &evt);
>>> + trace_smmuv3_record_event(sec_sid, smmu_event_string(info->type),
>>> + info->sid);
>>> + r = smmuv3_write_eventq(s, sec_sid, &evt);
>>> if (r != MEMTX_OK) {
>>> smmuv3_trigger_irq(s, SMMU_IRQ_GERROR, R_GERROR_EVENTQ_ABT_ERR_MASK);
>>> }
>>> @@ -917,6 +919,7 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
>>> 100 * sdev->cfg_cache_hits /
>>> (sdev->cfg_cache_hits + sdev->cfg_cache_misses));
>>> cfg = g_new0(SMMUTransCfg, 1);
>>> + cfg->sec_sid = SMMU_SEC_SID_NS;
>>>
>>> if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
>>> g_hash_table_insert(bc->configs, sdev, cfg);
>>> @@ -1074,7 +1077,8 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
>>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>>> SMMUEventInfo event = {.type = SMMU_EVT_NONE,
>>> .sid = sid,
>>> - .inval_ste_allowed = false};
>>> + .inval_ste_allowed = false,
>>> + .sec_sid = sec_sid};
>>> SMMUTranslationStatus status;
>>> SMMUTransCfg *cfg = NULL;
>>> IOMMUTLBEntry entry = {
>>> @@ -1176,7 +1180,9 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>> uint64_t num_pages, int stage)
>>> {
>>> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
>>> - SMMUEventInfo eventinfo = {.inval_ste_allowed = true};
>>> + SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>> + SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
>>> + .inval_ste_allowed = true};
>>> SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo);
>>> IOMMUTLBEvent event;
>>> uint8_t granule;
>>> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
>>> index 8135c0c7344..9c2cc131ab4 100644
>>> --- a/hw/arm/trace-events
>>> +++ b/hw/arm/trace-events
>>> @@ -40,7 +40,7 @@ smmuv3_cmdq_opcode(const char *opcode) "<--- %s"
>>> smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d "
>>> smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error on %s command execution: %d"
>>> smmuv3_write_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"
>>> -smmuv3_record_event(const char *type, uint32_t sid) "%s sid=0x%x"
>>> +smmuv3_record_event(int sec_sid, const char *type, uint32_t sid) "sec_sid=%d %s sid=0x%x"
>>> smmuv3_find_ste(uint16_t sid, uint32_t features, uint16_t sid_split) "sid=0x%x features:0x%x, sid_split:0x%x"
>>> smmuv3_find_ste_2lvl(uint64_t strtab_base, uint64_t l1ptr, int l1_ste_offset, uint64_t l2ptr, int l2_ste_offset, int max_l2_ste) "strtab_base:0x%"PRIx64" l1ptr:0x%"PRIx64" l1_off:0x%x, l2ptr:0x%"PRIx64" l2_off:0x%x max_l2_ste:%d"
>>> smmuv3_get_ste(uint64_t addr) "STE addr: 0x%"PRIx64
>>> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
>>> index 6ea40f6b074..ae1489717fe 100644
>>> --- a/include/hw/arm/smmu-common.h
>>> +++ b/include/hw/arm/smmu-common.h
>>> @@ -107,6 +107,7 @@ typedef struct SMMUS2Cfg {
>>> typedef struct SMMUTransCfg {
>>> /* Shared fields between stage-1 and stage-2. */
>>> SMMUStage stage; /* translation stage */
>>> + SMMUSecSID sec_sid; /* cached sec sid */
>> I am now wondering if sec_sid shall be part of the TransCfg as this is
>> never decoded from STE/CD, sin't it.
> Having slept over it, caching sed_id here indicates whether the secure
> stream table was used for decoding. So that can be considered as a
> result of the config decode process.
>
> a minor comment though, I think I would prefer having cfg->sec_sid
> populated in smmuv3_decode_config as the other cfg fields. Meaning I
> would rather add sed_sid to smmuv3_decode_config signature.
Thanks for the suggestion.
I'll add add sec_sid to smmuv3_decode_config as signature and do
something like `cfg->sec_sid = sec_sid` inside the function.
BTW as Mostafa and Eric discussed in previous thread, a check of sec_sid
would be placed at smmuv3_bank instead of asserting everywhere.
Thank you all for the review. I will start preparing the v5 according to
your feedback.
Tao
> Thanks
>
> Eric
>
>> Eric
>>> bool disabled; /* smmu is disabled */
>>> bool bypassed; /* translation is bypassed */
>>> bool aborted; /* translation is aborted */
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 07/31] hw/arm/smmu-common: Add security-aware address space selector
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (5 preceding siblings ...)
2026-02-21 10:02 ` [RFC v4 06/31] hw/arm/smmuv3: Track SEC_SID in configs and events Tao Tang
@ 2026-02-21 10:02 ` Tao Tang
2026-02-25 20:36 ` Pierrick Bouvier
2026-02-21 10:02 ` [RFC v4 08/31] hw/arm/smmuv3: Plumb transaction attributes into config helpers Tao Tang
` (23 subsequent siblings)
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:02 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Introduce SMMU_SEC_SID_S to represent SEC_SID == 1, meaning Secure. And
then provide smmu_get_address_space, a SMMU instance-based address space
selector. The helper now returns the per-device memory/secure-memory
AddressSpace and reports missing spaces.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmu-common.c | 17 +++++++++++++++++
include/hw/arm/smmu-common.h | 3 +++
2 files changed, 20 insertions(+)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 58c4452b1f5..3baba2a4c8e 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -30,6 +30,23 @@
#include "hw/arm/smmu-common.h"
#include "smmu-internal.h"
+AddressSpace *smmu_get_address_space(SMMUState *s, SMMUSecSID sec_sid)
+{
+ switch (sec_sid) {
+ case SMMU_SEC_SID_NS:
+ return &s->memory_as;
+ case SMMU_SEC_SID_S:
+ if (!s->secure_memory || s->secure_memory_as.root == NULL) {
+ warn_report("Secure address space requested but not available");
+ return NULL;
+ }
+ return &s->secure_memory_as;
+ default:
+ warn_report("Unknown SEC_SID value %d", sec_sid);
+ return NULL;
+ }
+}
+
/* IOTLB Management */
static guint smmu_iotlb_key_hash(gconstpointer v)
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index ae1489717fe..b3ca55effc5 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -43,6 +43,7 @@
/* StreamID Security state */
typedef enum SMMUSecSID {
SMMU_SEC_SID_NS = 0,
+ SMMU_SEC_SID_S,
SMMU_SEC_SID_NUM,
} SMMUSecSID;
@@ -189,6 +190,8 @@ struct SMMUBaseClass {
#define TYPE_ARM_SMMU "arm-smmu"
OBJECT_DECLARE_TYPE(SMMUState, SMMUBaseClass, ARM_SMMU)
+AddressSpace *smmu_get_address_space(SMMUState *s, SMMUSecSID sec_sid);
+
/* Return the SMMUPciBus handle associated to a PCI bus number */
SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num);
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 07/31] hw/arm/smmu-common: Add security-aware address space selector
2026-02-21 10:02 ` [RFC v4 07/31] hw/arm/smmu-common: Add security-aware address space selector Tao Tang
@ 2026-02-25 20:36 ` Pierrick Bouvier
0 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 20:36 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:02 AM, Tao Tang wrote:
> Introduce SMMU_SEC_SID_S to represent SEC_SID == 1, meaning Secure. And
> then provide smmu_get_address_space, a SMMU instance-based address space
> selector. The helper now returns the per-device memory/secure-memory
> AddressSpace and reports missing spaces.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 17 +++++++++++++++++
> include/hw/arm/smmu-common.h | 3 +++
> 2 files changed, 20 insertions(+)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index 58c4452b1f5..3baba2a4c8e 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -30,6 +30,23 @@
> #include "hw/arm/smmu-common.h"
> #include "smmu-internal.h"
>
> +AddressSpace *smmu_get_address_space(SMMUState *s, SMMUSecSID sec_sid)
> +{
> + switch (sec_sid) {
> + case SMMU_SEC_SID_NS:
> + return &s->memory_as;
> + case SMMU_SEC_SID_S:
> + if (!s->secure_memory || s->secure_memory_as.root == NULL) {
> + warn_report("Secure address space requested but not available");
> + return NULL;
> + }
Thinking about this one, I don't see any case where we would like to
silently return here.
Instead, could we check that directly in smmuv3_realize?
If arm-smmuv3.secure-impl is enabled, then we should have
s->secure_memory set accordingly.
As well, we can decide to enable secure-impl by default if secure-memory
is available. This way, it should do the right thing out of the box, and
assert with a good message if the machine configuration lacks something.
And user is still free to deactivate it with -global
arm-smmuv3.secure-impl=off if there is any reason to do so.
Do you see any reason to not enable secure-impl by default if
secure-memory is available?
Regards,
Pierrick
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 08/31] hw/arm/smmuv3: Plumb transaction attributes into config helpers
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (6 preceding siblings ...)
2026-02-21 10:02 ` [RFC v4 07/31] hw/arm/smmu-common: Add security-aware address space selector Tao Tang
@ 2026-02-21 10:02 ` Tao Tang
2026-02-25 20:52 ` Pierrick Bouvier
2026-02-25 20:55 ` Pierrick Bouvier
2026-02-21 10:02 ` [RFC v4 09/31] hw/arm/smmuv3: Enforce Secure stage 2 capability check when decoding STE Tao Tang
` (22 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:02 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
As a preliminary step towards a multi-security-state configuration
cache, introduce MemTxAttrs and AddressSpace * members to the
SMMUTransCfg struct. The goal is to cache these attributes so that
internal functions can use them directly.
To facilitate this, hw/arm/arm-security.h is now included in
smmu-common.h. This is a notable change, as it marks the first time
these Arm CPU-specific security space definitions are used outside of
cpu.h, making them more generally available for device models.
The decode helpers (smmu_get_ste, smmu_get_cd, smmu_find_ste,
smmuv3_get_config) are updated to use these new attributes for memory
accesses. This ensures that reads of SMMU structures from memory, such
as the Stream Table, use the correct security context.
For the special case of smmuv3-accel.c, we only support the NS-only path
for now. Therefore, we initialize a minimal cfg with sec_sid, txattrs,
and as for the NS-only accel path.
For now, the configuration cache lookup key remains unchanged and is
still based solely on the SMMUDevice pointer. The new attributes are
populated during a cache miss in smmuv3_get_config. And some paths still
rely on the NS-only address_space_memory, for example smmuv3_notify_iova
and get_pte(). These will be progressively converted in follow-up commits
to use an AddressSpace selected according to SEC_SID.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmu-common.c | 19 ++++++++++++++++++
hw/arm/smmuv3-accel.c | 12 +++++++++++-
hw/arm/smmuv3-internal.h | 3 ++-
hw/arm/smmuv3.c | 38 ++++++++++++++++++++++--------------
include/hw/arm/smmu-common.h | 12 ++++++++++++
5 files changed, 67 insertions(+), 17 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 3baba2a4c8e..b320aec8c60 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -30,6 +30,25 @@
#include "hw/arm/smmu-common.h"
#include "smmu-internal.h"
+ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid)
+{
+ switch (sec_sid) {
+ case SMMU_SEC_SID_S:
+ return ARMSS_Secure;
+ case SMMU_SEC_SID_NS:
+ default:
+ return ARMSS_NonSecure;
+ }
+}
+
+MemTxAttrs smmu_get_txattrs(SMMUSecSID sec_sid)
+{
+ return (MemTxAttrs) {
+ .secure = sec_sid > SMMU_SEC_SID_NS ? 1 : 0,
+ .space = smmu_get_security_space(sec_sid),
+ };
+}
+
AddressSpace *smmu_get_address_space(SMMUState *s, SMMUSecSID sec_sid)
{
switch (sec_sid) {
diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
index fdcb15005ea..9a41391826b 100644
--- a/hw/arm/smmuv3-accel.c
+++ b/hw/arm/smmuv3-accel.c
@@ -244,6 +244,16 @@ bool smmuv3_accel_install_ste(SMMUv3State *s, SMMUDevice *sdev, int sid,
const char *type;
STE ste;
SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ /*
+ * smmu_find_ste() requires a SMMUTransCfg to provide address space and
+ * transaction attributes for DMA reads. Only NS state is supported here.
+ */
+ SMMUState *bc = &s->smmu_state;
+ SMMUTransCfg cfg = {
+ .sec_sid = sec_sid,
+ .txattrs = smmu_get_txattrs(sec_sid),
+ .as = smmu_get_address_space(bc, sec_sid),
+ };
if (!accel || !accel->viommu) {
return true;
@@ -259,7 +269,7 @@ bool smmuv3_accel_install_ste(SMMUv3State *s, SMMUDevice *sdev, int sid,
return false;
}
- if (smmu_find_ste(sdev->smmu, sid, &ste, &event)) {
+ if (smmu_find_ste(sdev->smmu, sid, &ste, &event, &cfg)) {
/* No STE found, nothing to install */
return true;
}
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index a1071f7b689..6d29b9027f0 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -363,7 +363,8 @@ typedef struct SMMUEventInfo {
} while (0)
void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *event);
-int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event);
+int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event,
+ SMMUTransCfg *cfg);
static inline int oas2bits(int oas_field)
{
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 3438adcecd2..2192bec2368 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -347,14 +347,13 @@ static void smmuv3_reset(SMMUv3State *s)
}
static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
- SMMUEventInfo *event)
+ SMMUEventInfo *event, SMMUTransCfg *cfg)
{
int ret, i;
trace_smmuv3_get_ste(addr);
/* TODO: guarantee 64-bit single-copy atomicity */
- ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf),
- MEMTXATTRS_UNSPECIFIED);
+ ret = dma_memory_read(cfg->as, addr, buf, sizeof(*buf), cfg->txattrs);
if (ret != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR,
"Cannot fetch pte at address=0x%"PRIx64"\n", addr);
@@ -399,8 +398,7 @@ static int smmu_get_cd(SMMUv3State *s, STE *ste, SMMUTransCfg *cfg,
}
/* TODO: guarantee 64-bit single-copy atomicity */
- ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf),
- MEMTXATTRS_UNSPECIFIED);
+ ret = dma_memory_read(cfg->as, addr, buf, sizeof(*buf), cfg->txattrs);
if (ret != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR,
"Cannot fetch pte at address=0x%"PRIx64"\n", addr);
@@ -655,17 +653,19 @@ bad_ste:
* @sid: stream ID
* @ste: returned stream table entry
* @event: handle to an event info
+ * @cfg: translation configuration cache
*
* Supports linear and 2-level stream table
* Return 0 on success, -EINVAL otherwise
*/
-int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
+int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event,
+ SMMUTransCfg *cfg)
{
dma_addr_t addr, strtab_base;
uint32_t log2size;
int strtab_size_shift;
int ret;
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUSecSID sec_sid = cfg->sec_sid;
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
trace_smmuv3_find_ste(sid, bank->features, bank->sid_split);
@@ -693,8 +693,8 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
l2_ste_offset = sid & ((1 << bank->sid_split) - 1);
l1ptr = (dma_addr_t)(strtab_base + l1_ste_offset * sizeof(l1std));
/* TODO: guarantee 64-bit single-copy atomicity */
- ret = dma_memory_read(&address_space_memory, l1ptr, &l1std,
- sizeof(l1std), MEMTXATTRS_UNSPECIFIED);
+ ret = dma_memory_read(cfg->as, l1ptr, &l1std, sizeof(l1std),
+ cfg->txattrs);
if (ret != MEMTX_OK) {
qemu_log_mask(LOG_GUEST_ERROR,
"Could not read L1PTR at 0X%"PRIx64"\n", l1ptr);
@@ -736,7 +736,7 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
addr = strtab_base + sid * sizeof(*ste);
}
- if (smmu_get_ste(s, addr, ste, event)) {
+ if (smmu_get_ste(s, addr, ste, event, cfg)) {
return -EINVAL;
}
@@ -865,7 +865,7 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
/* ASID defaults to -1 (if s1 is not supported). */
cfg->asid = -1;
- ret = smmu_find_ste(s, sid, &ste, event);
+ ret = smmu_find_ste(s, sid, &ste, event, cfg);
if (ret) {
return ret;
}
@@ -899,7 +899,8 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
* decoding under the form of an SMMUTransCfg struct. The hash table is indexed
* by the SMMUDevice handle.
*/
-static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
+static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event,
+ SMMUSecSID sec_sid)
{
SMMUv3State *s = sdev->smmu;
SMMUState *bc = &s->smmu_state;
@@ -919,7 +920,14 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
100 * sdev->cfg_cache_hits /
(sdev->cfg_cache_hits + sdev->cfg_cache_misses));
cfg = g_new0(SMMUTransCfg, 1);
- cfg->sec_sid = SMMU_SEC_SID_NS;
+ cfg->sec_sid = sec_sid;
+ cfg->txattrs = smmu_get_txattrs(sec_sid);
+ cfg->as = smmu_get_address_space(bc, sec_sid);
+ cfg->ns_as = (sec_sid > SMMU_SEC_SID_NS)
+ ? smmu_get_address_space(bc, SMMU_SEC_SID_NS)
+ : cfg->as;
+ /* AddressSpace must be available, assert if not. */
+ g_assert(cfg->as && cfg->ns_as);
if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
g_hash_table_insert(bc->configs, sdev, cfg);
@@ -1101,7 +1109,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
goto epilogue;
}
- cfg = smmuv3_get_config(sdev, &event);
+ cfg = smmuv3_get_config(sdev, &event, sec_sid);
if (!cfg) {
status = SMMU_TRANS_ERROR;
goto epilogue;
@@ -1183,7 +1191,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
.inval_ste_allowed = true};
- SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo);
+ SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo, sec_sid);
IOMMUTLBEvent event;
uint8_t granule;
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index b3ca55effc5..7944e8d1b64 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -22,6 +22,7 @@
#include "hw/core/sysbus.h"
#include "hw/pci/pci.h"
#include "qom/object.h"
+#include "hw/arm/arm-security.h"
#define SMMU_PCI_BUS_MAX 256
#define SMMU_PCI_DEVFN_MAX 256
@@ -47,6 +48,9 @@ typedef enum SMMUSecSID {
SMMU_SEC_SID_NUM,
} SMMUSecSID;
+MemTxAttrs smmu_get_txattrs(SMMUSecSID sec_sid);
+ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid);
+
/*
* Page table walk error types
*/
@@ -124,6 +128,14 @@ typedef struct SMMUTransCfg {
SMMUTransTableInfo tt[2];
/* Used by stage-2 only. */
struct SMMUS2Cfg s2cfg;
+ MemTxAttrs txattrs; /* cached transaction attributes */
+ /*
+ * Cached AS related to the SEC_SID, which will be statically marked, and
+ * in future RME support it will be implemented as a dynamic switch.
+ */
+ AddressSpace *as;
+ /* Cached NS AS. It will be used if previous SEC_SID != SMMU_SEC_SID_NS. */
+ AddressSpace *ns_as;
} SMMUTransCfg;
typedef struct SMMUDevice {
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 08/31] hw/arm/smmuv3: Plumb transaction attributes into config helpers
2026-02-21 10:02 ` [RFC v4 08/31] hw/arm/smmuv3: Plumb transaction attributes into config helpers Tao Tang
@ 2026-02-25 20:52 ` Pierrick Bouvier
2026-02-27 15:20 ` Tao Tang
2026-02-25 20:55 ` Pierrick Bouvier
1 sibling, 1 reply; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 20:52 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:02 AM, Tao Tang wrote:
> As a preliminary step towards a multi-security-state configuration
> cache, introduce MemTxAttrs and AddressSpace * members to the
> SMMUTransCfg struct. The goal is to cache these attributes so that
> internal functions can use them directly.
>
> To facilitate this, hw/arm/arm-security.h is now included in
> smmu-common.h. This is a notable change, as it marks the first time
> these Arm CPU-specific security space definitions are used outside of
> cpu.h, making them more generally available for device models.
>
> The decode helpers (smmu_get_ste, smmu_get_cd, smmu_find_ste,
> smmuv3_get_config) are updated to use these new attributes for memory
> accesses. This ensures that reads of SMMU structures from memory, such
> as the Stream Table, use the correct security context.
>
> For the special case of smmuv3-accel.c, we only support the NS-only path
> for now. Therefore, we initialize a minimal cfg with sec_sid, txattrs,
> and as for the NS-only accel path.
>
> For now, the configuration cache lookup key remains unchanged and is
> still based solely on the SMMUDevice pointer. The new attributes are
> populated during a cache miss in smmuv3_get_config. And some paths still
> rely on the NS-only address_space_memory, for example smmuv3_notify_iova
> and get_pte(). These will be progressively converted in follow-up commits
> to use an AddressSpace selected according to SEC_SID.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 19 ++++++++++++++++++
> hw/arm/smmuv3-accel.c | 12 +++++++++++-
> hw/arm/smmuv3-internal.h | 3 ++-
> hw/arm/smmuv3.c | 38 ++++++++++++++++++++++--------------
> include/hw/arm/smmu-common.h | 12 ++++++++++++
> 5 files changed, 67 insertions(+), 17 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index 3baba2a4c8e..b320aec8c60 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -30,6 +30,25 @@
> #include "hw/arm/smmu-common.h"
> #include "smmu-internal.h"
>
> +ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid)
> +{
> + switch (sec_sid) {
> + case SMMU_SEC_SID_S:
> + return ARMSS_Secure;
> + case SMMU_SEC_SID_NS:
> + default:
> + return ARMSS_NonSecure;
> + }
> +}
> +
> +MemTxAttrs smmu_get_txattrs(SMMUSecSID sec_sid)
> +{
> + return (MemTxAttrs) {
> + .secure = sec_sid > SMMU_SEC_SID_NS ? 1 : 0,
> + .space = smmu_get_security_space(sec_sid),
> + };
> +}
> +
> AddressSpace *smmu_get_address_space(SMMUState *s, SMMUSecSID sec_sid)
> {
> switch (sec_sid) {
> diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
> index fdcb15005ea..9a41391826b 100644
> --- a/hw/arm/smmuv3-accel.c
> +++ b/hw/arm/smmuv3-accel.c
> @@ -244,6 +244,16 @@ bool smmuv3_accel_install_ste(SMMUv3State *s, SMMUDevice *sdev, int sid,
> const char *type;
> STE ste;
> SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + /*
> + * smmu_find_ste() requires a SMMUTransCfg to provide address space and
> + * transaction attributes for DMA reads. Only NS state is supported here.
> + */
> + SMMUState *bc = &s->smmu_state;
> + SMMUTransCfg cfg = {
> + .sec_sid = sec_sid,
> + .txattrs = smmu_get_txattrs(sec_sid),
> + .as = smmu_get_address_space(bc, sec_sid),
> + };
>
> if (!accel || !accel->viommu) {
> return true;
> @@ -259,7 +269,7 @@ bool smmuv3_accel_install_ste(SMMUv3State *s, SMMUDevice *sdev, int sid,
> return false;
> }
>
> - if (smmu_find_ste(sdev->smmu, sid, &ste, &event)) {
> + if (smmu_find_ste(sdev->smmu, sid, &ste, &event, &cfg)) {
> /* No STE found, nothing to install */
> return true;
> }
> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> index a1071f7b689..6d29b9027f0 100644
> --- a/hw/arm/smmuv3-internal.h
> +++ b/hw/arm/smmuv3-internal.h
> @@ -363,7 +363,8 @@ typedef struct SMMUEventInfo {
> } while (0)
>
> void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *event);
> -int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event);
> +int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event,
> + SMMUTransCfg *cfg);
>
> static inline int oas2bits(int oas_field)
> {
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 3438adcecd2..2192bec2368 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -347,14 +347,13 @@ static void smmuv3_reset(SMMUv3State *s)
> }
>
> static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
> - SMMUEventInfo *event)
> + SMMUEventInfo *event, SMMUTransCfg *cfg)
> {
> int ret, i;
>
> trace_smmuv3_get_ste(addr);
> /* TODO: guarantee 64-bit single-copy atomicity */
> - ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf),
> - MEMTXATTRS_UNSPECIFIED);
> + ret = dma_memory_read(cfg->as, addr, buf, sizeof(*buf), cfg->txattrs);
> if (ret != MEMTX_OK) {
> qemu_log_mask(LOG_GUEST_ERROR,
> "Cannot fetch pte at address=0x%"PRIx64"\n", addr);
> @@ -399,8 +398,7 @@ static int smmu_get_cd(SMMUv3State *s, STE *ste, SMMUTransCfg *cfg,
> }
>
> /* TODO: guarantee 64-bit single-copy atomicity */
> - ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf),
> - MEMTXATTRS_UNSPECIFIED);
> + ret = dma_memory_read(cfg->as, addr, buf, sizeof(*buf), cfg->txattrs);
> if (ret != MEMTX_OK) {
> qemu_log_mask(LOG_GUEST_ERROR,
> "Cannot fetch pte at address=0x%"PRIx64"\n", addr);
> @@ -655,17 +653,19 @@ bad_ste:
> * @sid: stream ID
> * @ste: returned stream table entry
> * @event: handle to an event info
> + * @cfg: translation configuration cache
> *
> * Supports linear and 2-level stream table
> * Return 0 on success, -EINVAL otherwise
> */
> -int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
> +int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event,
> + SMMUTransCfg *cfg)
> {
> dma_addr_t addr, strtab_base;
> uint32_t log2size;
> int strtab_size_shift;
> int ret;
> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUSecSID sec_sid = cfg->sec_sid;
> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>
> trace_smmuv3_find_ste(sid, bank->features, bank->sid_split);
> @@ -693,8 +693,8 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
> l2_ste_offset = sid & ((1 << bank->sid_split) - 1);
> l1ptr = (dma_addr_t)(strtab_base + l1_ste_offset * sizeof(l1std));
> /* TODO: guarantee 64-bit single-copy atomicity */
> - ret = dma_memory_read(&address_space_memory, l1ptr, &l1std,
> - sizeof(l1std), MEMTXATTRS_UNSPECIFIED);
> + ret = dma_memory_read(cfg->as, l1ptr, &l1std, sizeof(l1std),
> + cfg->txattrs);
> if (ret != MEMTX_OK) {
> qemu_log_mask(LOG_GUEST_ERROR,
> "Could not read L1PTR at 0X%"PRIx64"\n", l1ptr);
> @@ -736,7 +736,7 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste, SMMUEventInfo *event)
> addr = strtab_base + sid * sizeof(*ste);
> }
>
> - if (smmu_get_ste(s, addr, ste, event)) {
> + if (smmu_get_ste(s, addr, ste, event, cfg)) {
> return -EINVAL;
> }
>
> @@ -865,7 +865,7 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
> /* ASID defaults to -1 (if s1 is not supported). */
> cfg->asid = -1;
>
> - ret = smmu_find_ste(s, sid, &ste, event);
> + ret = smmu_find_ste(s, sid, &ste, event, cfg);
> if (ret) {
> return ret;
> }
> @@ -899,7 +899,8 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
> * decoding under the form of an SMMUTransCfg struct. The hash table is indexed
> * by the SMMUDevice handle.
> */
> -static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
> +static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event,
> + SMMUSecSID sec_sid)
> {
> SMMUv3State *s = sdev->smmu;
> SMMUState *bc = &s->smmu_state;
> @@ -919,7 +920,14 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
> 100 * sdev->cfg_cache_hits /
> (sdev->cfg_cache_hits + sdev->cfg_cache_misses));
> cfg = g_new0(SMMUTransCfg, 1);
> - cfg->sec_sid = SMMU_SEC_SID_NS;
> + cfg->sec_sid = sec_sid;
> + cfg->txattrs = smmu_get_txattrs(sec_sid);
> + cfg->as = smmu_get_address_space(bc, sec_sid);
> + cfg->ns_as = (sec_sid > SMMU_SEC_SID_NS)
> + ? smmu_get_address_space(bc, SMMU_SEC_SID_NS)
> + : cfg->as;
> + /* AddressSpace must be available, assert if not. */
> + g_assert(cfg->as && cfg->ns_as);
>
> if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
> g_hash_table_insert(bc->configs, sdev, cfg);
> @@ -1101,7 +1109,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> goto epilogue;
> }
>
> - cfg = smmuv3_get_config(sdev, &event);
> + cfg = smmuv3_get_config(sdev, &event, sec_sid);
> if (!cfg) {
> status = SMMU_TRANS_ERROR;
> goto epilogue;
> @@ -1183,7 +1191,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
> .inval_ste_allowed = true};
> - SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo);
> + SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo, sec_sid);
> IOMMUTLBEvent event;
> uint8_t granule;
>
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index b3ca55effc5..7944e8d1b64 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -22,6 +22,7 @@
> #include "hw/core/sysbus.h"
> #include "hw/pci/pci.h"
> #include "qom/object.h"
> +#include "hw/arm/arm-security.h"
>
> #define SMMU_PCI_BUS_MAX 256
> #define SMMU_PCI_DEVFN_MAX 256
> @@ -47,6 +48,9 @@ typedef enum SMMUSecSID {
> SMMU_SEC_SID_NUM,
> } SMMUSecSID;
>
> +MemTxAttrs smmu_get_txattrs(SMMUSecSID sec_sid);
> +ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid);
> +
> /*
> * Page table walk error types
> */
> @@ -124,6 +128,14 @@ typedef struct SMMUTransCfg {
> SMMUTransTableInfo tt[2];
> /* Used by stage-2 only. */
> struct SMMUS2Cfg s2cfg;
> + MemTxAttrs txattrs; /* cached transaction attributes */
> + /*
> + * Cached AS related to the SEC_SID, which will be statically marked, and
> + * in future RME support it will be implemented as a dynamic switch.
> + */
> + AddressSpace *as;
> + /* Cached NS AS. It will be used if previous SEC_SID != SMMU_SEC_SID_NS. */
> + AddressSpace *ns_as;
> } SMMUTransCfg;
>
As an alternative, you can simply pass SMMUState where it's missing
(like smmu_ptw_64_s2) and call smmu_get_address_space from there.
It will avoid having to keep this in cfg.
Maybe there is another reason I missed?
Regards,
Pierrick
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 08/31] hw/arm/smmuv3: Plumb transaction attributes into config helpers
2026-02-25 20:52 ` Pierrick Bouvier
@ 2026-02-27 15:20 ` Tao Tang
2026-02-27 22:02 ` Pierrick Bouvier
2026-03-02 15:59 ` Eric Auger
0 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-27 15:20 UTC (permalink / raw)
To: Pierrick Bouvier, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
Hi Pierrick,
On 2026/2/26 04:52, Pierrick Bouvier wrote:
> On 2/21/26 2:02 AM, Tao Tang wrote:
>> As a preliminary step towards a multi-security-state configuration
>> cache, introduce MemTxAttrs and AddressSpace * members to the
>> SMMUTransCfg struct. The goal is to cache these attributes so that
>> internal functions can use them directly.
>>
>> To facilitate this, hw/arm/arm-security.h is now included in
>> smmu-common.h. This is a notable change, as it marks the first time
>> these Arm CPU-specific security space definitions are used outside of
>> cpu.h, making them more generally available for device models.
>>
>> The decode helpers (smmu_get_ste, smmu_get_cd, smmu_find_ste,
>> smmuv3_get_config) are updated to use these new attributes for memory
>> accesses. This ensures that reads of SMMU structures from memory, such
>> as the Stream Table, use the correct security context.
>>
>> For the special case of smmuv3-accel.c, we only support the NS-only path
>> for now. Therefore, we initialize a minimal cfg with sec_sid, txattrs,
>> and as for the NS-only accel path.
>>
>> For now, the configuration cache lookup key remains unchanged and is
>> still based solely on the SMMUDevice pointer. The new attributes are
>> populated during a cache miss in smmuv3_get_config. And some paths still
>> rely on the NS-only address_space_memory, for example smmuv3_notify_iova
>> and get_pte(). These will be progressively converted in follow-up
>> commits
>> to use an AddressSpace selected according to SEC_SID.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmu-common.c | 19 ++++++++++++++++++
>> hw/arm/smmuv3-accel.c | 12 +++++++++++-
>> hw/arm/smmuv3-internal.h | 3 ++-
>> hw/arm/smmuv3.c | 38 ++++++++++++++++++++++--------------
>> include/hw/arm/smmu-common.h | 12 ++++++++++++
>> 5 files changed, 67 insertions(+), 17 deletions(-)
>>
>> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
>> index 3baba2a4c8e..b320aec8c60 100644
>> --- a/hw/arm/smmu-common.c
>> +++ b/hw/arm/smmu-common.c
>> @@ -30,6 +30,25 @@
>> #include "hw/arm/smmu-common.h"
>> #include "smmu-internal.h"
>> +ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid)
>> +{
>> + switch (sec_sid) {
>> + case SMMU_SEC_SID_S:
>> + return ARMSS_Secure;
>> + case SMMU_SEC_SID_NS:
>> + default:
>> + return ARMSS_NonSecure;
>> + }
>> +}
>> +
>> +MemTxAttrs smmu_get_txattrs(SMMUSecSID sec_sid)
>> +{
>> + return (MemTxAttrs) {
>> + .secure = sec_sid > SMMU_SEC_SID_NS ? 1 : 0,
>> + .space = smmu_get_security_space(sec_sid),
>> + };
>> +}
>> +
>> AddressSpace *smmu_get_address_space(SMMUState *s, SMMUSecSID sec_sid)
>> {
>> switch (sec_sid) {
>> diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
>> index fdcb15005ea..9a41391826b 100644
>> --- a/hw/arm/smmuv3-accel.c
>> +++ b/hw/arm/smmuv3-accel.c
>> @@ -244,6 +244,16 @@ bool smmuv3_accel_install_ste(SMMUv3State *s,
>> SMMUDevice *sdev, int sid,
>> const char *type;
>> STE ste;
>> SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> + /*
>> + * smmu_find_ste() requires a SMMUTransCfg to provide address
>> space and
>> + * transaction attributes for DMA reads. Only NS state is
>> supported here.
>> + */
>> + SMMUState *bc = &s->smmu_state;
>> + SMMUTransCfg cfg = {
>> + .sec_sid = sec_sid,
>> + .txattrs = smmu_get_txattrs(sec_sid),
>> + .as = smmu_get_address_space(bc, sec_sid),
>> + };
>> if (!accel || !accel->viommu) {
>> return true;
>> @@ -259,7 +269,7 @@ bool smmuv3_accel_install_ste(SMMUv3State *s,
>> SMMUDevice *sdev, int sid,
>> return false;
>> }
>> - if (smmu_find_ste(sdev->smmu, sid, &ste, &event)) {
>> + if (smmu_find_ste(sdev->smmu, sid, &ste, &event, &cfg)) {
>> /* No STE found, nothing to install */
>> return true;
>> }
>> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
>> index a1071f7b689..6d29b9027f0 100644
>> --- a/hw/arm/smmuv3-internal.h
>> +++ b/hw/arm/smmuv3-internal.h
>> @@ -363,7 +363,8 @@ typedef struct SMMUEventInfo {
>> } while (0)
>> void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *event);
>> -int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>> SMMUEventInfo *event);
>> +int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>> SMMUEventInfo *event,
>> + SMMUTransCfg *cfg);
>> static inline int oas2bits(int oas_field)
>> {
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index 3438adcecd2..2192bec2368 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -347,14 +347,13 @@ static void smmuv3_reset(SMMUv3State *s)
>> }
>> static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
>> - SMMUEventInfo *event)
>> + SMMUEventInfo *event, SMMUTransCfg *cfg)
>> {
>> int ret, i;
>> trace_smmuv3_get_ste(addr);
>> /* TODO: guarantee 64-bit single-copy atomicity */
>> - ret = dma_memory_read(&address_space_memory, addr, buf,
>> sizeof(*buf),
>> - MEMTXATTRS_UNSPECIFIED);
>> + ret = dma_memory_read(cfg->as, addr, buf, sizeof(*buf),
>> cfg->txattrs);
>> if (ret != MEMTX_OK) {
>> qemu_log_mask(LOG_GUEST_ERROR,
>> "Cannot fetch pte at address=0x%"PRIx64"\n",
>> addr);
>> @@ -399,8 +398,7 @@ static int smmu_get_cd(SMMUv3State *s, STE *ste,
>> SMMUTransCfg *cfg,
>> }
>> /* TODO: guarantee 64-bit single-copy atomicity */
>> - ret = dma_memory_read(&address_space_memory, addr, buf,
>> sizeof(*buf),
>> - MEMTXATTRS_UNSPECIFIED);
>> + ret = dma_memory_read(cfg->as, addr, buf, sizeof(*buf),
>> cfg->txattrs);
>> if (ret != MEMTX_OK) {
>> qemu_log_mask(LOG_GUEST_ERROR,
>> "Cannot fetch pte at address=0x%"PRIx64"\n",
>> addr);
>> @@ -655,17 +653,19 @@ bad_ste:
>> * @sid: stream ID
>> * @ste: returned stream table entry
>> * @event: handle to an event info
>> + * @cfg: translation configuration cache
>> *
>> * Supports linear and 2-level stream table
>> * Return 0 on success, -EINVAL otherwise
>> */
>> -int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>> SMMUEventInfo *event)
>> +int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>> SMMUEventInfo *event,
>> + SMMUTransCfg *cfg)
>> {
>> dma_addr_t addr, strtab_base;
>> uint32_t log2size;
>> int strtab_size_shift;
>> int ret;
>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> + SMMUSecSID sec_sid = cfg->sec_sid;
>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>> trace_smmuv3_find_ste(sid, bank->features, bank->sid_split);
>> @@ -693,8 +693,8 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid,
>> STE *ste, SMMUEventInfo *event)
>> l2_ste_offset = sid & ((1 << bank->sid_split) - 1);
>> l1ptr = (dma_addr_t)(strtab_base + l1_ste_offset *
>> sizeof(l1std));
>> /* TODO: guarantee 64-bit single-copy atomicity */
>> - ret = dma_memory_read(&address_space_memory, l1ptr, &l1std,
>> - sizeof(l1std), MEMTXATTRS_UNSPECIFIED);
>> + ret = dma_memory_read(cfg->as, l1ptr, &l1std, sizeof(l1std),
>> + cfg->txattrs);
>> if (ret != MEMTX_OK) {
>> qemu_log_mask(LOG_GUEST_ERROR,
>> "Could not read L1PTR at 0X%"PRIx64"\n",
>> l1ptr);
>> @@ -736,7 +736,7 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid,
>> STE *ste, SMMUEventInfo *event)
>> addr = strtab_base + sid * sizeof(*ste);
>> }
>> - if (smmu_get_ste(s, addr, ste, event)) {
>> + if (smmu_get_ste(s, addr, ste, event, cfg)) {
>> return -EINVAL;
>> }
>> @@ -865,7 +865,7 @@ static int
>> smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
>> /* ASID defaults to -1 (if s1 is not supported). */
>> cfg->asid = -1;
>> - ret = smmu_find_ste(s, sid, &ste, event);
>> + ret = smmu_find_ste(s, sid, &ste, event, cfg);
>> if (ret) {
>> return ret;
>> }
>> @@ -899,7 +899,8 @@ static int smmuv3_decode_config(IOMMUMemoryRegion
>> *mr, SMMUTransCfg *cfg,
>> * decoding under the form of an SMMUTransCfg struct. The hash
>> table is indexed
>> * by the SMMUDevice handle.
>> */
>> -static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev,
>> SMMUEventInfo *event)
>> +static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev,
>> SMMUEventInfo *event,
>> + SMMUSecSID sec_sid)
>> {
>> SMMUv3State *s = sdev->smmu;
>> SMMUState *bc = &s->smmu_state;
>> @@ -919,7 +920,14 @@ static SMMUTransCfg
>> *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
>> 100 * sdev->cfg_cache_hits /
>> (sdev->cfg_cache_hits +
>> sdev->cfg_cache_misses));
>> cfg = g_new0(SMMUTransCfg, 1);
>> - cfg->sec_sid = SMMU_SEC_SID_NS;
>> + cfg->sec_sid = sec_sid;
>> + cfg->txattrs = smmu_get_txattrs(sec_sid);
>> + cfg->as = smmu_get_address_space(bc, sec_sid);
>> + cfg->ns_as = (sec_sid > SMMU_SEC_SID_NS)
>> + ? smmu_get_address_space(bc, SMMU_SEC_SID_NS)
>> + : cfg->as;
>> + /* AddressSpace must be available, assert if not. */
>> + g_assert(cfg->as && cfg->ns_as);
>> if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
>> g_hash_table_insert(bc->configs, sdev, cfg);
>> @@ -1101,7 +1109,7 @@ static IOMMUTLBEntry
>> smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
>> goto epilogue;
>> }
>> - cfg = smmuv3_get_config(sdev, &event);
>> + cfg = smmuv3_get_config(sdev, &event, sec_sid);
>> if (!cfg) {
>> status = SMMU_TRANS_ERROR;
>> goto epilogue;
>> @@ -1183,7 +1191,7 @@ static void
>> smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>> SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
>> .inval_ste_allowed = true};
>> - SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo);
>> + SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo, sec_sid);
>> IOMMUTLBEvent event;
>> uint8_t granule;
>> diff --git a/include/hw/arm/smmu-common.h
>> b/include/hw/arm/smmu-common.h
>> index b3ca55effc5..7944e8d1b64 100644
>> --- a/include/hw/arm/smmu-common.h
>> +++ b/include/hw/arm/smmu-common.h
>> @@ -22,6 +22,7 @@
>> #include "hw/core/sysbus.h"
>> #include "hw/pci/pci.h"
>> #include "qom/object.h"
>> +#include "hw/arm/arm-security.h"
>> #define SMMU_PCI_BUS_MAX 256
>> #define SMMU_PCI_DEVFN_MAX 256
>> @@ -47,6 +48,9 @@ typedef enum SMMUSecSID {
>> SMMU_SEC_SID_NUM,
>> } SMMUSecSID;
>> +MemTxAttrs smmu_get_txattrs(SMMUSecSID sec_sid);
>> +ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid);
>> +
>> /*
>> * Page table walk error types
>> */
>> @@ -124,6 +128,14 @@ typedef struct SMMUTransCfg {
>> SMMUTransTableInfo tt[2];
>> /* Used by stage-2 only. */
>> struct SMMUS2Cfg s2cfg;
>> + MemTxAttrs txattrs; /* cached transaction attributes */
>> + /*
>> + * Cached AS related to the SEC_SID, which will be statically
>> marked, and
>> + * in future RME support it will be implemented as a dynamic
>> switch.
>> + */
>> + AddressSpace *as;
>> + /* Cached NS AS. It will be used if previous SEC_SID !=
>> SMMU_SEC_SID_NS. */
>> + AddressSpace *ns_as;
>> } SMMUTransCfg;
>>
>
> As an alternative, you can simply pass SMMUState where it's missing
> (like smmu_ptw_64_s2) and call smmu_get_address_space from there.
> It will avoid having to keep this in cfg.
>
> Maybe there is another reason I missed?
My original motivation for having an extra ns_as (and caching
as/txattrs) was tied to the architectural semantics: a transaction being
"secure" does not automatically mean the walk can access Secure PAS.
Whether the walk can touch Secure PAS (or is effectively constrained to
Non-secure PAS) is determined by the STE/CD fields and the page-table
attributes at each level; in an RME setup we would also add GPC checks.
So, if the combined state ends up forcing Non-secure PAS, the intent was
to reuse a preselected NS address space rather than re-deriving it
repeatedly during the walk.
That said, I agree that keeping as/txattrs (and ns_as) inside
SMMUTransCfg is debatable, and it also blurs “decoded translation
config” versus “per-walk execution context”. Eric previously suggested
caching as and MemTxAttrs in v2 to streamline the hot path:
https://lore.kernel.org/qemu-devel/4b90afba-d708-4628-a087-c16829ee0512@redhat.com/
But given your feedback, I’m leaning toward your alternative. In
particular, with your recent commit (53b54a8 "add memory regions as
property for an SMMU instance"), selecting the appropriate AddressSpace
is very cheap. So I think it’s reasonable to refactor now: pass
SMMUState where it’s missing (e.g. in smmu_ptw_64_s2) and compute
AddressSpace/MemTxAttrs on-demand based on the current walk state,
instead of caching them in SMMUTransCfg.
I’ll rework the patch accordingly, and I’d also very much welcome any
further comments or suggestions from others.
>
> Regards,
> Pierrick
Thanks,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 08/31] hw/arm/smmuv3: Plumb transaction attributes into config helpers
2026-02-27 15:20 ` Tao Tang
@ 2026-02-27 22:02 ` Pierrick Bouvier
2026-03-02 15:59 ` Eric Auger
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-27 22:02 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/27/26 7:20 AM, Tao Tang wrote:
> Hi Pierrick,
>
> On 2026/2/26 04:52, Pierrick Bouvier wrote:
>> On 2/21/26 2:02 AM, Tao Tang wrote:
>>> As a preliminary step towards a multi-security-state configuration
>>> cache, introduce MemTxAttrs and AddressSpace * members to the
>>> SMMUTransCfg struct. The goal is to cache these attributes so that
>>> internal functions can use them directly.
>>>
>>> To facilitate this, hw/arm/arm-security.h is now included in
>>> smmu-common.h. This is a notable change, as it marks the first time
>>> these Arm CPU-specific security space definitions are used outside of
>>> cpu.h, making them more generally available for device models.
>>>
>>> The decode helpers (smmu_get_ste, smmu_get_cd, smmu_find_ste,
>>> smmuv3_get_config) are updated to use these new attributes for memory
>>> accesses. This ensures that reads of SMMU structures from memory, such
>>> as the Stream Table, use the correct security context.
>>>
>>> For the special case of smmuv3-accel.c, we only support the NS-only path
>>> for now. Therefore, we initialize a minimal cfg with sec_sid, txattrs,
>>> and as for the NS-only accel path.
>>>
>>> For now, the configuration cache lookup key remains unchanged and is
>>> still based solely on the SMMUDevice pointer. The new attributes are
>>> populated during a cache miss in smmuv3_get_config. And some paths still
>>> rely on the NS-only address_space_memory, for example smmuv3_notify_iova
>>> and get_pte(). These will be progressively converted in follow-up
>>> commits
>>> to use an AddressSpace selected according to SEC_SID.
>>>
>>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>>> ---
>>> hw/arm/smmu-common.c | 19 ++++++++++++++++++
>>> hw/arm/smmuv3-accel.c | 12 +++++++++++-
>>> hw/arm/smmuv3-internal.h | 3 ++-
>>> hw/arm/smmuv3.c | 38 ++++++++++++++++++++++--------------
>>> include/hw/arm/smmu-common.h | 12 ++++++++++++
>>> 5 files changed, 67 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
>>> index 3baba2a4c8e..b320aec8c60 100644
>>> --- a/hw/arm/smmu-common.c
>>> +++ b/hw/arm/smmu-common.c
>>> @@ -30,6 +30,25 @@
>>> #include "hw/arm/smmu-common.h"
>>> #include "smmu-internal.h"
>>> +ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid)
>>> +{
>>> + switch (sec_sid) {
>>> + case SMMU_SEC_SID_S:
>>> + return ARMSS_Secure;
>>> + case SMMU_SEC_SID_NS:
>>> + default:
>>> + return ARMSS_NonSecure;
>>> + }
>>> +}
>>> +
>>> +MemTxAttrs smmu_get_txattrs(SMMUSecSID sec_sid)
>>> +{
>>> + return (MemTxAttrs) {
>>> + .secure = sec_sid > SMMU_SEC_SID_NS ? 1 : 0,
>>> + .space = smmu_get_security_space(sec_sid),
>>> + };
>>> +}
>>> +
>>> AddressSpace *smmu_get_address_space(SMMUState *s, SMMUSecSID sec_sid)
>>> {
>>> switch (sec_sid) {
>>> diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
>>> index fdcb15005ea..9a41391826b 100644
>>> --- a/hw/arm/smmuv3-accel.c
>>> +++ b/hw/arm/smmuv3-accel.c
>>> @@ -244,6 +244,16 @@ bool smmuv3_accel_install_ste(SMMUv3State *s,
>>> SMMUDevice *sdev, int sid,
>>> const char *type;
>>> STE ste;
>>> SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>> + /*
>>> + * smmu_find_ste() requires a SMMUTransCfg to provide address
>>> space and
>>> + * transaction attributes for DMA reads. Only NS state is
>>> supported here.
>>> + */
>>> + SMMUState *bc = &s->smmu_state;
>>> + SMMUTransCfg cfg = {
>>> + .sec_sid = sec_sid,
>>> + .txattrs = smmu_get_txattrs(sec_sid),
>>> + .as = smmu_get_address_space(bc, sec_sid),
>>> + };
>>> if (!accel || !accel->viommu) {
>>> return true;
>>> @@ -259,7 +269,7 @@ bool smmuv3_accel_install_ste(SMMUv3State *s,
>>> SMMUDevice *sdev, int sid,
>>> return false;
>>> }
>>> - if (smmu_find_ste(sdev->smmu, sid, &ste, &event)) {
>>> + if (smmu_find_ste(sdev->smmu, sid, &ste, &event, &cfg)) {
>>> /* No STE found, nothing to install */
>>> return true;
>>> }
>>> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
>>> index a1071f7b689..6d29b9027f0 100644
>>> --- a/hw/arm/smmuv3-internal.h
>>> +++ b/hw/arm/smmuv3-internal.h
>>> @@ -363,7 +363,8 @@ typedef struct SMMUEventInfo {
>>> } while (0)
>>> void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *event);
>>> -int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>>> SMMUEventInfo *event);
>>> +int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>>> SMMUEventInfo *event,
>>> + SMMUTransCfg *cfg);
>>> static inline int oas2bits(int oas_field)
>>> {
>>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>>> index 3438adcecd2..2192bec2368 100644
>>> --- a/hw/arm/smmuv3.c
>>> +++ b/hw/arm/smmuv3.c
>>> @@ -347,14 +347,13 @@ static void smmuv3_reset(SMMUv3State *s)
>>> }
>>> static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
>>> - SMMUEventInfo *event)
>>> + SMMUEventInfo *event, SMMUTransCfg *cfg)
>>> {
>>> int ret, i;
>>> trace_smmuv3_get_ste(addr);
>>> /* TODO: guarantee 64-bit single-copy atomicity */
>>> - ret = dma_memory_read(&address_space_memory, addr, buf,
>>> sizeof(*buf),
>>> - MEMTXATTRS_UNSPECIFIED);
>>> + ret = dma_memory_read(cfg->as, addr, buf, sizeof(*buf),
>>> cfg->txattrs);
>>> if (ret != MEMTX_OK) {
>>> qemu_log_mask(LOG_GUEST_ERROR,
>>> "Cannot fetch pte at address=0x%"PRIx64"\n",
>>> addr);
>>> @@ -399,8 +398,7 @@ static int smmu_get_cd(SMMUv3State *s, STE *ste,
>>> SMMUTransCfg *cfg,
>>> }
>>> /* TODO: guarantee 64-bit single-copy atomicity */
>>> - ret = dma_memory_read(&address_space_memory, addr, buf,
>>> sizeof(*buf),
>>> - MEMTXATTRS_UNSPECIFIED);
>>> + ret = dma_memory_read(cfg->as, addr, buf, sizeof(*buf),
>>> cfg->txattrs);
>>> if (ret != MEMTX_OK) {
>>> qemu_log_mask(LOG_GUEST_ERROR,
>>> "Cannot fetch pte at address=0x%"PRIx64"\n",
>>> addr);
>>> @@ -655,17 +653,19 @@ bad_ste:
>>> * @sid: stream ID
>>> * @ste: returned stream table entry
>>> * @event: handle to an event info
>>> + * @cfg: translation configuration cache
>>> *
>>> * Supports linear and 2-level stream table
>>> * Return 0 on success, -EINVAL otherwise
>>> */
>>> -int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>>> SMMUEventInfo *event)
>>> +int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>>> SMMUEventInfo *event,
>>> + SMMUTransCfg *cfg)
>>> {
>>> dma_addr_t addr, strtab_base;
>>> uint32_t log2size;
>>> int strtab_size_shift;
>>> int ret;
>>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>> + SMMUSecSID sec_sid = cfg->sec_sid;
>>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>>> trace_smmuv3_find_ste(sid, bank->features, bank->sid_split);
>>> @@ -693,8 +693,8 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid,
>>> STE *ste, SMMUEventInfo *event)
>>> l2_ste_offset = sid & ((1 << bank->sid_split) - 1);
>>> l1ptr = (dma_addr_t)(strtab_base + l1_ste_offset *
>>> sizeof(l1std));
>>> /* TODO: guarantee 64-bit single-copy atomicity */
>>> - ret = dma_memory_read(&address_space_memory, l1ptr, &l1std,
>>> - sizeof(l1std), MEMTXATTRS_UNSPECIFIED);
>>> + ret = dma_memory_read(cfg->as, l1ptr, &l1std, sizeof(l1std),
>>> + cfg->txattrs);
>>> if (ret != MEMTX_OK) {
>>> qemu_log_mask(LOG_GUEST_ERROR,
>>> "Could not read L1PTR at 0X%"PRIx64"\n",
>>> l1ptr);
>>> @@ -736,7 +736,7 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid,
>>> STE *ste, SMMUEventInfo *event)
>>> addr = strtab_base + sid * sizeof(*ste);
>>> }
>>> - if (smmu_get_ste(s, addr, ste, event)) {
>>> + if (smmu_get_ste(s, addr, ste, event, cfg)) {
>>> return -EINVAL;
>>> }
>>> @@ -865,7 +865,7 @@ static int
>>> smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
>>> /* ASID defaults to -1 (if s1 is not supported). */
>>> cfg->asid = -1;
>>> - ret = smmu_find_ste(s, sid, &ste, event);
>>> + ret = smmu_find_ste(s, sid, &ste, event, cfg);
>>> if (ret) {
>>> return ret;
>>> }
>>> @@ -899,7 +899,8 @@ static int smmuv3_decode_config(IOMMUMemoryRegion
>>> *mr, SMMUTransCfg *cfg,
>>> * decoding under the form of an SMMUTransCfg struct. The hash
>>> table is indexed
>>> * by the SMMUDevice handle.
>>> */
>>> -static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev,
>>> SMMUEventInfo *event)
>>> +static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev,
>>> SMMUEventInfo *event,
>>> + SMMUSecSID sec_sid)
>>> {
>>> SMMUv3State *s = sdev->smmu;
>>> SMMUState *bc = &s->smmu_state;
>>> @@ -919,7 +920,14 @@ static SMMUTransCfg
>>> *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
>>> 100 * sdev->cfg_cache_hits /
>>> (sdev->cfg_cache_hits +
>>> sdev->cfg_cache_misses));
>>> cfg = g_new0(SMMUTransCfg, 1);
>>> - cfg->sec_sid = SMMU_SEC_SID_NS;
>>> + cfg->sec_sid = sec_sid;
>>> + cfg->txattrs = smmu_get_txattrs(sec_sid);
>>> + cfg->as = smmu_get_address_space(bc, sec_sid);
>>> + cfg->ns_as = (sec_sid > SMMU_SEC_SID_NS)
>>> + ? smmu_get_address_space(bc, SMMU_SEC_SID_NS)
>>> + : cfg->as;
>>> + /* AddressSpace must be available, assert if not. */
>>> + g_assert(cfg->as && cfg->ns_as);
>>> if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
>>> g_hash_table_insert(bc->configs, sdev, cfg);
>>> @@ -1101,7 +1109,7 @@ static IOMMUTLBEntry
>>> smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
>>> goto epilogue;
>>> }
>>> - cfg = smmuv3_get_config(sdev, &event);
>>> + cfg = smmuv3_get_config(sdev, &event, sec_sid);
>>> if (!cfg) {
>>> status = SMMU_TRANS_ERROR;
>>> goto epilogue;
>>> @@ -1183,7 +1191,7 @@ static void
>>> smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>> SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>> SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
>>> .inval_ste_allowed = true};
>>> - SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo);
>>> + SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo, sec_sid);
>>> IOMMUTLBEvent event;
>>> uint8_t granule;
>>> diff --git a/include/hw/arm/smmu-common.h
>>> b/include/hw/arm/smmu-common.h
>>> index b3ca55effc5..7944e8d1b64 100644
>>> --- a/include/hw/arm/smmu-common.h
>>> +++ b/include/hw/arm/smmu-common.h
>>> @@ -22,6 +22,7 @@
>>> #include "hw/core/sysbus.h"
>>> #include "hw/pci/pci.h"
>>> #include "qom/object.h"
>>> +#include "hw/arm/arm-security.h"
>>> #define SMMU_PCI_BUS_MAX 256
>>> #define SMMU_PCI_DEVFN_MAX 256
>>> @@ -47,6 +48,9 @@ typedef enum SMMUSecSID {
>>> SMMU_SEC_SID_NUM,
>>> } SMMUSecSID;
>>> +MemTxAttrs smmu_get_txattrs(SMMUSecSID sec_sid);
>>> +ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid);
>>> +
>>> /*
>>> * Page table walk error types
>>> */
>>> @@ -124,6 +128,14 @@ typedef struct SMMUTransCfg {
>>> SMMUTransTableInfo tt[2];
>>> /* Used by stage-2 only. */
>>> struct SMMUS2Cfg s2cfg;
>>> + MemTxAttrs txattrs; /* cached transaction attributes */
>>> + /*
>>> + * Cached AS related to the SEC_SID, which will be statically
>>> marked, and
>>> + * in future RME support it will be implemented as a dynamic
>>> switch.
>>> + */
>>> + AddressSpace *as;
>>> + /* Cached NS AS. It will be used if previous SEC_SID !=
>>> SMMU_SEC_SID_NS. */
>>> + AddressSpace *ns_as;
>>> } SMMUTransCfg;
>>>
>>
>> As an alternative, you can simply pass SMMUState where it's missing
>> (like smmu_ptw_64_s2) and call smmu_get_address_space from there.
>> It will avoid having to keep this in cfg.
>>
>> Maybe there is another reason I missed?
>
>
> My original motivation for having an extra ns_as (and caching
> as/txattrs) was tied to the architectural semantics: a transaction being
> "secure" does not automatically mean the walk can access Secure PAS.
> Whether the walk can touch Secure PAS (or is effectively constrained to
> Non-secure PAS) is determined by the STE/CD fields and the page-table
> attributes at each level; in an RME setup we would also add GPC checks.
> So, if the combined state ends up forcing Non-secure PAS, the intent was
> to reuse a preselected NS address space rather than re-deriving it
> repeatedly during the walk.
>
> That said, I agree that keeping as/txattrs (and ns_as) inside
> SMMUTransCfg is debatable, and it also blurs “decoded translation
> config” versus “per-walk execution context”. Eric previously suggested
> caching as and MemTxAttrs in v2 to streamline the hot path:
>
> https://lore.kernel.org/qemu-devel/4b90afba-d708-4628-a087-c16829ee0512@redhat.com/
>
>
> But given your feedback, I’m leaning toward your alternative. In
> particular, with your recent commit (53b54a8 "add memory regions as
> property for an SMMU instance"), selecting the appropriate AddressSpace
> is very cheap. So I think it’s reasonable to refactor now: pass
> SMMUState where it’s missing (e.g. in smmu_ptw_64_s2) and compute
> AddressSpace/MemTxAttrs on-demand based on the current walk state,
> instead of caching them in SMMUTransCfg.
>
It's indeed trivial to derive address space from cfg->sec_sid, and
clearer since we'll always provide a sec_sid to access it, so I don't
see any good reason left to cache it.
Eric, would you be ok with it?
>
> I’ll rework the patch accordingly, and I’d also very much welcome any
> further comments or suggestions from others.
>
>
>>
>> Regards,
>> Pierrick
>
>
> Thanks,
>
> Tao
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 08/31] hw/arm/smmuv3: Plumb transaction attributes into config helpers
2026-02-27 15:20 ` Tao Tang
2026-02-27 22:02 ` Pierrick Bouvier
@ 2026-03-02 15:59 ` Eric Auger
1 sibling, 0 replies; 136+ messages in thread
From: Eric Auger @ 2026-03-02 15:59 UTC (permalink / raw)
To: Tao Tang, Pierrick Bouvier, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/27/26 4:20 PM, Tao Tang wrote:
> Hi Pierrick,
>
> On 2026/2/26 04:52, Pierrick Bouvier wrote:
>> On 2/21/26 2:02 AM, Tao Tang wrote:
>>> As a preliminary step towards a multi-security-state configuration
>>> cache, introduce MemTxAttrs and AddressSpace * members to the
>>> SMMUTransCfg struct. The goal is to cache these attributes so that
>>> internal functions can use them directly.
>>>
>>> To facilitate this, hw/arm/arm-security.h is now included in
>>> smmu-common.h. This is a notable change, as it marks the first time
>>> these Arm CPU-specific security space definitions are used outside of
>>> cpu.h, making them more generally available for device models.
>>>
>>> The decode helpers (smmu_get_ste, smmu_get_cd, smmu_find_ste,
>>> smmuv3_get_config) are updated to use these new attributes for memory
>>> accesses. This ensures that reads of SMMU structures from memory, such
>>> as the Stream Table, use the correct security context.
>>>
>>> For the special case of smmuv3-accel.c, we only support the NS-only
>>> path
>>> for now. Therefore, we initialize a minimal cfg with sec_sid, txattrs,
>>> and as for the NS-only accel path.
>>>
>>> For now, the configuration cache lookup key remains unchanged and is
>>> still based solely on the SMMUDevice pointer. The new attributes are
>>> populated during a cache miss in smmuv3_get_config. And some paths
>>> still
>>> rely on the NS-only address_space_memory, for example
>>> smmuv3_notify_iova
>>> and get_pte(). These will be progressively converted in follow-up
>>> commits
>>> to use an AddressSpace selected according to SEC_SID.
>>>
>>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>>> ---
>>> hw/arm/smmu-common.c | 19 ++++++++++++++++++
>>> hw/arm/smmuv3-accel.c | 12 +++++++++++-
>>> hw/arm/smmuv3-internal.h | 3 ++-
>>> hw/arm/smmuv3.c | 38
>>> ++++++++++++++++++++++--------------
>>> include/hw/arm/smmu-common.h | 12 ++++++++++++
>>> 5 files changed, 67 insertions(+), 17 deletions(-)
>>>
>>> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
>>> index 3baba2a4c8e..b320aec8c60 100644
>>> --- a/hw/arm/smmu-common.c
>>> +++ b/hw/arm/smmu-common.c
>>> @@ -30,6 +30,25 @@
>>> #include "hw/arm/smmu-common.h"
>>> #include "smmu-internal.h"
>>> +ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid)
>>> +{
>>> + switch (sec_sid) {
>>> + case SMMU_SEC_SID_S:
>>> + return ARMSS_Secure;
>>> + case SMMU_SEC_SID_NS:
>>> + default:
>>> + return ARMSS_NonSecure;
>>> + }
>>> +}
>>> +
>>> +MemTxAttrs smmu_get_txattrs(SMMUSecSID sec_sid)
>>> +{
>>> + return (MemTxAttrs) {
>>> + .secure = sec_sid > SMMU_SEC_SID_NS ? 1 : 0,
>>> + .space = smmu_get_security_space(sec_sid),
>>> + };
>>> +}
>>> +
>>> AddressSpace *smmu_get_address_space(SMMUState *s, SMMUSecSID
>>> sec_sid)
>>> {
>>> switch (sec_sid) {
>>> diff --git a/hw/arm/smmuv3-accel.c b/hw/arm/smmuv3-accel.c
>>> index fdcb15005ea..9a41391826b 100644
>>> --- a/hw/arm/smmuv3-accel.c
>>> +++ b/hw/arm/smmuv3-accel.c
>>> @@ -244,6 +244,16 @@ bool smmuv3_accel_install_ste(SMMUv3State *s,
>>> SMMUDevice *sdev, int sid,
>>> const char *type;
>>> STE ste;
>>> SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>> + /*
>>> + * smmu_find_ste() requires a SMMUTransCfg to provide address
>>> space and
>>> + * transaction attributes for DMA reads. Only NS state is
>>> supported here.
>>> + */
>>> + SMMUState *bc = &s->smmu_state;
>>> + SMMUTransCfg cfg = {
>>> + .sec_sid = sec_sid,
>>> + .txattrs = smmu_get_txattrs(sec_sid),
>>> + .as = smmu_get_address_space(bc, sec_sid),
>>> + };
>>> if (!accel || !accel->viommu) {
>>> return true;
>>> @@ -259,7 +269,7 @@ bool smmuv3_accel_install_ste(SMMUv3State *s,
>>> SMMUDevice *sdev, int sid,
>>> return false;
>>> }
>>> - if (smmu_find_ste(sdev->smmu, sid, &ste, &event)) {
>>> + if (smmu_find_ste(sdev->smmu, sid, &ste, &event, &cfg)) {
>>> /* No STE found, nothing to install */
>>> return true;
>>> }
>>> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
>>> index a1071f7b689..6d29b9027f0 100644
>>> --- a/hw/arm/smmuv3-internal.h
>>> +++ b/hw/arm/smmuv3-internal.h
>>> @@ -363,7 +363,8 @@ typedef struct SMMUEventInfo {
>>> } while (0)
>>> void smmuv3_record_event(SMMUv3State *s, SMMUEventInfo *event);
>>> -int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>>> SMMUEventInfo *event);
>>> +int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>>> SMMUEventInfo *event,
>>> + SMMUTransCfg *cfg);
>>> static inline int oas2bits(int oas_field)
>>> {
>>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>>> index 3438adcecd2..2192bec2368 100644
>>> --- a/hw/arm/smmuv3.c
>>> +++ b/hw/arm/smmuv3.c
>>> @@ -347,14 +347,13 @@ static void smmuv3_reset(SMMUv3State *s)
>>> }
>>> static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
>>> - SMMUEventInfo *event)
>>> + SMMUEventInfo *event, SMMUTransCfg *cfg)
>>> {
>>> int ret, i;
>>> trace_smmuv3_get_ste(addr);
>>> /* TODO: guarantee 64-bit single-copy atomicity */
>>> - ret = dma_memory_read(&address_space_memory, addr, buf,
>>> sizeof(*buf),
>>> - MEMTXATTRS_UNSPECIFIED);
>>> + ret = dma_memory_read(cfg->as, addr, buf, sizeof(*buf),
>>> cfg->txattrs);
>>> if (ret != MEMTX_OK) {
>>> qemu_log_mask(LOG_GUEST_ERROR,
>>> "Cannot fetch pte at address=0x%"PRIx64"\n",
>>> addr);
>>> @@ -399,8 +398,7 @@ static int smmu_get_cd(SMMUv3State *s, STE *ste,
>>> SMMUTransCfg *cfg,
>>> }
>>> /* TODO: guarantee 64-bit single-copy atomicity */
>>> - ret = dma_memory_read(&address_space_memory, addr, buf,
>>> sizeof(*buf),
>>> - MEMTXATTRS_UNSPECIFIED);
>>> + ret = dma_memory_read(cfg->as, addr, buf, sizeof(*buf),
>>> cfg->txattrs);
>>> if (ret != MEMTX_OK) {
>>> qemu_log_mask(LOG_GUEST_ERROR,
>>> "Cannot fetch pte at address=0x%"PRIx64"\n",
>>> addr);
>>> @@ -655,17 +653,19 @@ bad_ste:
>>> * @sid: stream ID
>>> * @ste: returned stream table entry
>>> * @event: handle to an event info
>>> + * @cfg: translation configuration cache
>>> *
>>> * Supports linear and 2-level stream table
>>> * Return 0 on success, -EINVAL otherwise
>>> */
>>> -int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>>> SMMUEventInfo *event)
>>> +int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
>>> SMMUEventInfo *event,
>>> + SMMUTransCfg *cfg)
>>> {
>>> dma_addr_t addr, strtab_base;
>>> uint32_t log2size;
>>> int strtab_size_shift;
>>> int ret;
>>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>> + SMMUSecSID sec_sid = cfg->sec_sid;
>>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>>> trace_smmuv3_find_ste(sid, bank->features, bank->sid_split);
>>> @@ -693,8 +693,8 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid,
>>> STE *ste, SMMUEventInfo *event)
>>> l2_ste_offset = sid & ((1 << bank->sid_split) - 1);
>>> l1ptr = (dma_addr_t)(strtab_base + l1_ste_offset *
>>> sizeof(l1std));
>>> /* TODO: guarantee 64-bit single-copy atomicity */
>>> - ret = dma_memory_read(&address_space_memory, l1ptr, &l1std,
>>> - sizeof(l1std), MEMTXATTRS_UNSPECIFIED);
>>> + ret = dma_memory_read(cfg->as, l1ptr, &l1std, sizeof(l1std),
>>> + cfg->txattrs);
>>> if (ret != MEMTX_OK) {
>>> qemu_log_mask(LOG_GUEST_ERROR,
>>> "Could not read L1PTR at 0X%"PRIx64"\n",
>>> l1ptr);
>>> @@ -736,7 +736,7 @@ int smmu_find_ste(SMMUv3State *s, uint32_t sid,
>>> STE *ste, SMMUEventInfo *event)
>>> addr = strtab_base + sid * sizeof(*ste);
>>> }
>>> - if (smmu_get_ste(s, addr, ste, event)) {
>>> + if (smmu_get_ste(s, addr, ste, event, cfg)) {
>>> return -EINVAL;
>>> }
>>> @@ -865,7 +865,7 @@ static int
>>> smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
>>> /* ASID defaults to -1 (if s1 is not supported). */
>>> cfg->asid = -1;
>>> - ret = smmu_find_ste(s, sid, &ste, event);
>>> + ret = smmu_find_ste(s, sid, &ste, event, cfg);
>>> if (ret) {
>>> return ret;
>>> }
>>> @@ -899,7 +899,8 @@ static int
>>> smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
>>> * decoding under the form of an SMMUTransCfg struct. The hash
>>> table is indexed
>>> * by the SMMUDevice handle.
>>> */
>>> -static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev,
>>> SMMUEventInfo *event)
>>> +static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev,
>>> SMMUEventInfo *event,
>>> + SMMUSecSID sec_sid)
>>> {
>>> SMMUv3State *s = sdev->smmu;
>>> SMMUState *bc = &s->smmu_state;
>>> @@ -919,7 +920,14 @@ static SMMUTransCfg
>>> *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event)
>>> 100 * sdev->cfg_cache_hits /
>>> (sdev->cfg_cache_hits +
>>> sdev->cfg_cache_misses));
>>> cfg = g_new0(SMMUTransCfg, 1);
>>> - cfg->sec_sid = SMMU_SEC_SID_NS;
>>> + cfg->sec_sid = sec_sid;
>>> + cfg->txattrs = smmu_get_txattrs(sec_sid);
>>> + cfg->as = smmu_get_address_space(bc, sec_sid);
>>> + cfg->ns_as = (sec_sid > SMMU_SEC_SID_NS)
>>> + ? smmu_get_address_space(bc, SMMU_SEC_SID_NS)
>>> + : cfg->as;
>>> + /* AddressSpace must be available, assert if not. */
>>> + g_assert(cfg->as && cfg->ns_as);
>>> if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
>>> g_hash_table_insert(bc->configs, sdev, cfg);
>>> @@ -1101,7 +1109,7 @@ static IOMMUTLBEntry
>>> smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
>>> goto epilogue;
>>> }
>>> - cfg = smmuv3_get_config(sdev, &event);
>>> + cfg = smmuv3_get_config(sdev, &event, sec_sid);
>>> if (!cfg) {
>>> status = SMMU_TRANS_ERROR;
>>> goto epilogue;
>>> @@ -1183,7 +1191,7 @@ static void
>>> smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>> SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>> SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
>>> .inval_ste_allowed = true};
>>> - SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo);
>>> + SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo, sec_sid);
>>> IOMMUTLBEvent event;
>>> uint8_t granule;
>>> diff --git a/include/hw/arm/smmu-common.h
>>> b/include/hw/arm/smmu-common.h
>>> index b3ca55effc5..7944e8d1b64 100644
>>> --- a/include/hw/arm/smmu-common.h
>>> +++ b/include/hw/arm/smmu-common.h
>>> @@ -22,6 +22,7 @@
>>> #include "hw/core/sysbus.h"
>>> #include "hw/pci/pci.h"
>>> #include "qom/object.h"
>>> +#include "hw/arm/arm-security.h"
>>> #define SMMU_PCI_BUS_MAX 256
>>> #define SMMU_PCI_DEVFN_MAX 256
>>> @@ -47,6 +48,9 @@ typedef enum SMMUSecSID {
>>> SMMU_SEC_SID_NUM,
>>> } SMMUSecSID;
>>> +MemTxAttrs smmu_get_txattrs(SMMUSecSID sec_sid);
>>> +ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid);
>>> +
>>> /*
>>> * Page table walk error types
>>> */
>>> @@ -124,6 +128,14 @@ typedef struct SMMUTransCfg {
>>> SMMUTransTableInfo tt[2];
>>> /* Used by stage-2 only. */
>>> struct SMMUS2Cfg s2cfg;
>>> + MemTxAttrs txattrs; /* cached transaction attributes */
>>> + /*
>>> + * Cached AS related to the SEC_SID, which will be statically
>>> marked, and
>>> + * in future RME support it will be implemented as a dynamic
>>> switch.
>>> + */
>>> + AddressSpace *as;
>>> + /* Cached NS AS. It will be used if previous SEC_SID !=
>>> SMMU_SEC_SID_NS. */
>>> + AddressSpace *ns_as;
>>> } SMMUTransCfg;
>>>
>>
>> As an alternative, you can simply pass SMMUState where it's missing
>> (like smmu_ptw_64_s2) and call smmu_get_address_space from there.
>> It will avoid having to keep this in cfg.
>>
>> Maybe there is another reason I missed?
>
>
> My original motivation for having an extra ns_as (and caching
> as/txattrs) was tied to the architectural semantics: a transaction
> being "secure" does not automatically mean the walk can access Secure
> PAS. Whether the walk can touch Secure PAS (or is effectively
> constrained to Non-secure PAS) is determined by the STE/CD fields and
> the page-table attributes at each level; in an RME setup we would also
> add GPC checks. So, if the combined state ends up forcing Non-secure
> PAS, the intent was to reuse a preselected NS address space rather
> than re-deriving it repeatedly during the walk.
>
> That said, I agree that keeping as/txattrs (and ns_as) inside
> SMMUTransCfg is debatable, and it also blurs “decoded translation
> config” versus “per-walk execution context”. Eric previously suggested
> caching as and MemTxAttrs in v2 to streamline the hot path:
I was rather suggesting splitting the patch to ease the review ;-)
>
> https://lore.kernel.org/qemu-devel/4b90afba-d708-4628-a087-c16829ee0512@redhat.com/
>
>
>
> But given your feedback, I’m leaning toward your alternative. In
> particular, with your recent commit (53b54a8 "add memory regions as
> property for an SMMU instance"), selecting the appropriate
> AddressSpace is very cheap. So I think it’s reasonable to refactor
> now: pass SMMUState where it’s missing (e.g. in smmu_ptw_64_s2) and
> compute AddressSpace/MemTxAttrs on-demand based on the current walk
> state, instead of caching them in SMMUTransCfg.
>
SMMUTransCfg is rather supposed to cache info that were grabbed from
STE/CD with smmuv3_decode_config(). sec_sid rather is a property of the
DMA initiator [28/31] and thus does not relate to the SMMUTransConfig I
think. So I agree with Pierrick.
Thanks
Eric
>
> I’ll rework the patch accordingly, and I’d also very much welcome any
> further comments or suggestions from others.
>
>
>>
>> Regards,
>> Pierrick
>
>
> Thanks,
>
> Tao
>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 08/31] hw/arm/smmuv3: Plumb transaction attributes into config helpers
2026-02-21 10:02 ` [RFC v4 08/31] hw/arm/smmuv3: Plumb transaction attributes into config helpers Tao Tang
2026-02-25 20:52 ` Pierrick Bouvier
@ 2026-02-25 20:55 ` Pierrick Bouvier
2026-02-27 15:35 ` Tao Tang
1 sibling, 1 reply; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 20:55 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:02 AM, Tao Tang wrote:
> As a preliminary step towards a multi-security-state configuration
> cache, introduce MemTxAttrs and AddressSpace * members to the
> SMMUTransCfg struct. The goal is to cache these attributes so that
> internal functions can use them directly.
>
> To facilitate this, hw/arm/arm-security.h is now included in
> smmu-common.h. This is a notable change, as it marks the first time
> these Arm CPU-specific security space definitions are used outside of
> cpu.h, making them more generally available for device models.
>
> The decode helpers (smmu_get_ste, smmu_get_cd, smmu_find_ste,
> smmuv3_get_config) are updated to use these new attributes for memory
> accesses. This ensures that reads of SMMU structures from memory, such
> as the Stream Table, use the correct security context.
>
> For the special case of smmuv3-accel.c, we only support the NS-only path
> for now. Therefore, we initialize a minimal cfg with sec_sid, txattrs,
> and as for the NS-only accel path.
>
> For now, the configuration cache lookup key remains unchanged and is
> still based solely on the SMMUDevice pointer. The new attributes are
> populated during a cache miss in smmuv3_get_config. And some paths still
> rely on the NS-only address_space_memory, for example smmuv3_notify_iova
> and get_pte(). These will be progressively converted in follow-up commits
> to use an AddressSpace selected according to SEC_SID.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 19 ++++++++++++++++++
> hw/arm/smmuv3-accel.c | 12 +++++++++++-
> hw/arm/smmuv3-internal.h | 3 ++-
> hw/arm/smmuv3.c | 38 ++++++++++++++++++++++--------------
> include/hw/arm/smmu-common.h | 12 ++++++++++++
> 5 files changed, 67 insertions(+), 17 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index 3baba2a4c8e..b320aec8c60 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -30,6 +30,25 @@
> #include "hw/arm/smmu-common.h"
> #include "smmu-internal.h"
>
> +ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid)
> +{
> + switch (sec_sid) {
> + case SMMU_SEC_SID_S:
> + return ARMSS_Secure;
> + case SMMU_SEC_SID_NS:
> + default:
> + return ARMSS_NonSecure;
> + }
> +}
> +
Would that be possible to add all switch values, and use
g_assert_not_reached() for SMMU_SEC_SID_NUM.
This way, when adding SMMU_SEC_SID_R, we'll be directly blocked at
compilation because case is missing.
Regards,
Pierrick
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 08/31] hw/arm/smmuv3: Plumb transaction attributes into config helpers
2026-02-25 20:55 ` Pierrick Bouvier
@ 2026-02-27 15:35 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-27 15:35 UTC (permalink / raw)
To: Pierrick Bouvier, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
Hi Pierrick,
On 2026/2/26 04:55, Pierrick Bouvier wrote:
> On 2/21/26 2:02 AM, Tao Tang wrote:
>> As a preliminary step towards a multi-security-state configuration
>> cache, introduce MemTxAttrs and AddressSpace * members to the
>> SMMUTransCfg struct. The goal is to cache these attributes so that
>> internal functions can use them directly.
>>
>> To facilitate this, hw/arm/arm-security.h is now included in
>> smmu-common.h. This is a notable change, as it marks the first time
>> these Arm CPU-specific security space definitions are used outside of
>> cpu.h, making them more generally available for device models.
>>
>> The decode helpers (smmu_get_ste, smmu_get_cd, smmu_find_ste,
>> smmuv3_get_config) are updated to use these new attributes for memory
>> accesses. This ensures that reads of SMMU structures from memory, such
>> as the Stream Table, use the correct security context.
>>
>> For the special case of smmuv3-accel.c, we only support the NS-only path
>> for now. Therefore, we initialize a minimal cfg with sec_sid, txattrs,
>> and as for the NS-only accel path.
>>
>> For now, the configuration cache lookup key remains unchanged and is
>> still based solely on the SMMUDevice pointer. The new attributes are
>> populated during a cache miss in smmuv3_get_config. And some paths still
>> rely on the NS-only address_space_memory, for example smmuv3_notify_iova
>> and get_pte(). These will be progressively converted in follow-up
>> commits
>> to use an AddressSpace selected according to SEC_SID.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmu-common.c | 19 ++++++++++++++++++
>> hw/arm/smmuv3-accel.c | 12 +++++++++++-
>> hw/arm/smmuv3-internal.h | 3 ++-
>> hw/arm/smmuv3.c | 38 ++++++++++++++++++++++--------------
>> include/hw/arm/smmu-common.h | 12 ++++++++++++
>> 5 files changed, 67 insertions(+), 17 deletions(-)
>>
>> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
>> index 3baba2a4c8e..b320aec8c60 100644
>> --- a/hw/arm/smmu-common.c
>> +++ b/hw/arm/smmu-common.c
>> @@ -30,6 +30,25 @@
>> #include "hw/arm/smmu-common.h"
>> #include "smmu-internal.h"
>> +ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid)
>> +{
>> + switch (sec_sid) {
>> + case SMMU_SEC_SID_S:
>> + return ARMSS_Secure;
>> + case SMMU_SEC_SID_NS:
>> + default:
>> + return ARMSS_NonSecure;
>> + }
>> +}
>> +
>
> Would that be possible to add all switch values, and use
> g_assert_not_reached() for SMMU_SEC_SID_NUM.
> This way, when adding SMMU_SEC_SID_R, we'll be directly blocked at
> compilation because case is missing.
>
Thanks for the suggestion.
I'll refactor it like below:
switch (sec_sid) {
case SMMU_SEC_SID_S:
return ARMSS_Secure;
case SMMU_SEC_SID_NS:
return ARMSS_NonSecure;
case SMMU_SEC_SID_NUM:
g_assert_not_reached();
}
g_assert_not_reached();
> Regards,
> Pierrick
Thanks,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 09/31] hw/arm/smmuv3: Enforce Secure stage 2 capability check when decoding STE
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (7 preceding siblings ...)
2026-02-21 10:02 ` [RFC v4 08/31] hw/arm/smmuv3: Plumb transaction attributes into config helpers Tao Tang
@ 2026-02-21 10:02 ` Tao Tang
2026-02-25 20:52 ` Pierrick Bouvier
` (2 more replies)
2026-02-21 10:14 ` [RFC v4 10/31] hw/arm/smmu-common: Key configuration cache on SMMUDevice and SEC_SID Tao Tang
` (21 subsequent siblings)
30 siblings, 3 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:02 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
When decoding a Stream Table Entry (STE) from the Secure stream table
that enables stage-2 translation, verify that the SMMU implementation
advertises Secure stage-2 support via S_IDR1.SEL2. If stage-2 is
requested but S_IDR1.SEL2 is 0, mark the STE as ILLEGAL.
This implements the requirement from the Arm SMMUv3 architecture
specification (IHI 0070G.b, Section 5.2, Page 218) that a Secure STE
with stage-2 enabled is only valid when the implementation supports
Secure stage-2 translation.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 2192bec2368..d011357253e 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -623,6 +623,16 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
if (ret) {
goto bad_ste;
}
+
+ /*
+ * Stage 2 is implemented but Secure stage 2 is not supported while
+ * STE is from Secure stream table. STE is ILLEGAL in this case
+ * according to (IHI 0070G.b) 5.2 STE, Stream Table Entry, Page 218.
+ */
+ if ((cfg->sec_sid == SMMU_SEC_SID_S) &&
+ !(FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1, SEL2))) {
+ goto bad_ste;
+ }
}
/* Multiple context descriptors require SubstreamID support */
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 09/31] hw/arm/smmuv3: Enforce Secure stage 2 capability check when decoding STE
2026-02-21 10:02 ` [RFC v4 09/31] hw/arm/smmuv3: Enforce Secure stage 2 capability check when decoding STE Tao Tang
@ 2026-02-25 20:52 ` Pierrick Bouvier
2026-02-27 14:39 ` Mostafa Saleh
2026-03-02 16:48 ` Eric Auger
2 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 20:52 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:02 AM, Tao Tang wrote:
> When decoding a Stream Table Entry (STE) from the Secure stream table
> that enables stage-2 translation, verify that the SMMU implementation
> advertises Secure stage-2 support via S_IDR1.SEL2. If stage-2 is
> requested but S_IDR1.SEL2 is 0, mark the STE as ILLEGAL.
>
> This implements the requirement from the Arm SMMUv3 architecture
> specification (IHI 0070G.b, Section 5.2, Page 218) that a Secure STE
> with stage-2 enabled is only valid when the implementation supports
> Secure stage-2 translation.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 09/31] hw/arm/smmuv3: Enforce Secure stage 2 capability check when decoding STE
2026-02-21 10:02 ` [RFC v4 09/31] hw/arm/smmuv3: Enforce Secure stage 2 capability check when decoding STE Tao Tang
2026-02-25 20:52 ` Pierrick Bouvier
@ 2026-02-27 14:39 ` Mostafa Saleh
2026-03-01 14:02 ` Tao Tang
2026-03-02 16:48 ` Eric Auger
2 siblings, 1 reply; 136+ messages in thread
From: Mostafa Saleh @ 2026-02-27 14:39 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sat, Feb 21, 2026 at 06:02:28PM +0800, Tao Tang wrote:
> When decoding a Stream Table Entry (STE) from the Secure stream table
> that enables stage-2 translation, verify that the SMMU implementation
> advertises Secure stage-2 support via S_IDR1.SEL2. If stage-2 is
> requested but S_IDR1.SEL2 is 0, mark the STE as ILLEGAL.
>
> This implements the requirement from the Arm SMMUv3 architecture
> specification (IHI 0070G.b, Section 5.2, Page 218) that a Secure STE
> with stage-2 enabled is only valid when the implementation supports
> Secure stage-2 translation.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 2192bec2368..d011357253e 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -623,6 +623,16 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
> if (ret) {
> goto bad_ste;
> }
> +
> + /*
> + * Stage 2 is implemented but Secure stage 2 is not supported while
> + * STE is from Secure stream table. STE is ILLEGAL in this case
> + * according to (IHI 0070G.b) 5.2 STE, Stream Table Entry, Page 218.
> + */
> + if ((cfg->sec_sid == SMMU_SEC_SID_S) &&
> + !(FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1, SEL2))) {
> + goto bad_ste;
> + }
The IDR is not currently set, we can just safely return bad_ste for
“SMMU_SEC_SID_S”, no need to complicate things until SEL2 is supported.
Thanks,
Mostafa
> }
>
> /* Multiple context descriptors require SubstreamID support */
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 09/31] hw/arm/smmuv3: Enforce Secure stage 2 capability check when decoding STE
2026-02-27 14:39 ` Mostafa Saleh
@ 2026-03-01 14:02 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-01 14:02 UTC (permalink / raw)
To: Mostafa Saleh
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
Hi Mostafa,
On 2026/2/27 PM10:39, Mostafa Saleh wrote:
> On Sat, Feb 21, 2026 at 06:02:28PM +0800, Tao Tang wrote:
>> When decoding a Stream Table Entry (STE) from the Secure stream table
>> that enables stage-2 translation, verify that the SMMU implementation
>> advertises Secure stage-2 support via S_IDR1.SEL2. If stage-2 is
>> requested but S_IDR1.SEL2 is 0, mark the STE as ILLEGAL.
>>
>> This implements the requirement from the Arm SMMUv3 architecture
>> specification (IHI 0070G.b, Section 5.2, Page 218) that a Secure STE
>> with stage-2 enabled is only valid when the implementation supports
>> Secure stage-2 translation.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmuv3.c | 10 ++++++++++
>> 1 file changed, 10 insertions(+)
>>
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index 2192bec2368..d011357253e 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -623,6 +623,16 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
>> if (ret) {
>> goto bad_ste;
>> }
>> +
>> + /*
>> + * Stage 2 is implemented but Secure stage 2 is not supported while
>> + * STE is from Secure stream table. STE is ILLEGAL in this case
>> + * according to (IHI 0070G.b) 5.2 STE, Stream Table Entry, Page 218.
>> + */
>> + if ((cfg->sec_sid == SMMU_SEC_SID_S) &&
>> + !(FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1, SEL2))) {
>> + goto bad_ste;
>> + }
> The IDR is not currently set, we can just safely return bad_ste for
> “SMMU_SEC_SID_S”, no need to complicate things until SEL2 is supported.
Agreed. I’ll simplify this to unconditionally treat Secure STE
requesting stage-2 as ILLEGAL, and revisit the SEL2 check once SEL2
support is implemented.
> Thanks,
> Mostafa
Best regards,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 09/31] hw/arm/smmuv3: Enforce Secure stage 2 capability check when decoding STE
2026-02-21 10:02 ` [RFC v4 09/31] hw/arm/smmuv3: Enforce Secure stage 2 capability check when decoding STE Tao Tang
2026-02-25 20:52 ` Pierrick Bouvier
2026-02-27 14:39 ` Mostafa Saleh
@ 2026-03-02 16:48 ` Eric Auger
2026-03-04 16:09 ` Tao Tang
2 siblings, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-02 16:48 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 2/21/26 11:02 AM, Tao Tang wrote:
> When decoding a Stream Table Entry (STE) from the Secure stream table
> that enables stage-2 translation, verify that the SMMU implementation
> advertises Secure stage-2 support via S_IDR1.SEL2. If stage-2 is
> requested but S_IDR1.SEL2 is 0, mark the STE as ILLEGAL.
>
> This implements the requirement from the Arm SMMUv3 architecture
> specification (IHI 0070G.b, Section 5.2, Page 218) that a Secure STE
> with stage-2 enabled is only valid when the implementation supports
> Secure stage-2 translation.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 2192bec2368..d011357253e 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -623,6 +623,16 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
I think I would rather pass the sec_sid as a parameter, indicating which
secure stream table shall be used for ste decoding
> if (ret) {
> goto bad_ste;
> }
> +
> + /*
> + * Stage 2 is implemented but Secure stage 2 is not supported while
> + * STE is from Secure stream table. STE is ILLEGAL in this case
> + * according to (IHI 0070G.b) 5.2 STE, Stream Table Entry, Page 218.
would reuse the spec full terminology:
I would explicitly tell explicitly: " it is ILLEGAL to set STE.Config ==
0b11x."
> + */
> + if ((cfg->sec_sid == SMMU_SEC_SID_S) &&
> + !(FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1, SEL2))) {
> + goto bad_ste;
> + }
> }
>
> /* Multiple context descriptors require SubstreamID support */
Otherwise looks good
Eric
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 09/31] hw/arm/smmuv3: Enforce Secure stage 2 capability check when decoding STE
2026-03-02 16:48 ` Eric Auger
@ 2026-03-04 16:09 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-04 16:09 UTC (permalink / raw)
To: eric.auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi Eric,
On 2026/3/3 AM12:48, Eric Auger wrote:
> On 2/21/26 11:02 AM, Tao Tang wrote:
>> When decoding a Stream Table Entry (STE) from the Secure stream table
>> that enables stage-2 translation, verify that the SMMU implementation
>> advertises Secure stage-2 support via S_IDR1.SEL2. If stage-2 is
>> requested but S_IDR1.SEL2 is 0, mark the STE as ILLEGAL.
>>
>> This implements the requirement from the Arm SMMUv3 architecture
>> specification (IHI 0070G.b, Section 5.2, Page 218) that a Secure STE
>> with stage-2 enabled is only valid when the implementation supports
>> Secure stage-2 translation.
>>
>> Signed-off-by: Tao Tang<tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmuv3.c | 10 ++++++++++
>> 1 file changed, 10 insertions(+)
>>
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index 2192bec2368..d011357253e 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -623,6 +623,16 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
> I think I would rather pass the sec_sid as a parameter, indicating which
> secure stream table shall be used for ste decoding
>> if (ret) {
>> goto bad_ste;
>> }
>> +
>> + /*
>> + * Stage 2 is implemented but Secure stage 2 is not supported while
>> + * STE is from Secure stream table. STE is ILLEGAL in this case
>> + * according to (IHI 0070G.b) 5.2 STE, Stream Table Entry, Page 218.
> would reuse the spec full terminology:
> I would explicitly tell explicitly: " it is ILLEGAL to set STE.Config ==
> 0b11x."
>> + */
>> + if ((cfg->sec_sid == SMMU_SEC_SID_S) &&
>> + !(FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1, SEL2))) {
>> + goto bad_ste;
>> + }
>> }
>>
>> /* Multiple context descriptors require SubstreamID support */
> Otherwise looks good
Thanks for your review.
I’ll rework decode_ste() to take sec_sid as a parameter, and explicitly
state the illegal encoding.
Best regards,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 10/31] hw/arm/smmu-common: Key configuration cache on SMMUDevice and SEC_SID
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (8 preceding siblings ...)
2026-02-21 10:02 ` [RFC v4 09/31] hw/arm/smmuv3: Enforce Secure stage 2 capability check when decoding STE Tao Tang
@ 2026-02-21 10:14 ` Tao Tang
2026-02-25 21:01 ` Pierrick Bouvier
2026-03-02 16:54 ` Eric Auger
2026-02-21 10:15 ` [RFC v4 11/31] hw/arm/smmu: Add PTE NS/NSTable helpers Tao Tang
` (20 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:14 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Adapt the configuration cache to support multiple security states by
introducing a composite key, SMMUConfigKey. This key combines the
SMMUDevice with SEC_SID, preventing aliasing between Secure and
Non-secure configurations for the same device, also the future Realm and
Root configurations.
The cache lookup, insertion, and invalidation mechanisms are updated
to use this new keying infrastructure. This change is critical for
ensuring correct translation when a device is active in more than one
security world.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Link: https://lore.kernel.org/qemu-devel/a9a840a6-c65f-4352-9a49-ddd1b5483f43@redhat.com/
---
hw/arm/smmu-common.c | 45 ++++++++++++++++++++++++++++++++++--
hw/arm/smmuv3.c | 13 +++++++----
include/hw/arm/smmu-common.h | 7 ++++++
3 files changed, 58 insertions(+), 7 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index b320aec8c60..a732303b28b 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -30,6 +30,26 @@
#include "hw/arm/smmu-common.h"
#include "smmu-internal.h"
+/* Configuration Cache Management */
+static guint smmu_config_key_hash(gconstpointer key)
+{
+ const SMMUConfigKey *k = key;
+ return g_direct_hash(k->sdev) ^ (guint)k->sec_sid;
+}
+
+static gboolean smmu_config_key_equal(gconstpointer a, gconstpointer b)
+{
+ const SMMUConfigKey *ka = a;
+ const SMMUConfigKey *kb = b;
+ return ka->sdev == kb->sdev && ka->sec_sid == kb->sec_sid;
+}
+
+SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID sec_sid)
+{
+ SMMUConfigKey key = {.sdev = sdev, .sec_sid = sec_sid};
+ return key;
+}
+
ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid)
{
switch (sec_sid) {
@@ -265,7 +285,8 @@ static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
static gboolean
smmu_hash_remove_by_sid_range(gpointer key, gpointer value, gpointer user_data)
{
- SMMUDevice *sdev = (SMMUDevice *)key;
+ SMMUConfigKey *config_key = (SMMUConfigKey *)key;
+ SMMUDevice *sdev = config_key->sdev;
uint32_t sid = smmu_get_sid(sdev);
SMMUSIDRange *sid_range = (SMMUSIDRange *)user_data;
@@ -283,6 +304,24 @@ void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range)
&sid_range);
}
+static gboolean smmu_hash_remove_by_sdev(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ SMMUConfigKey *config_key = (SMMUConfigKey *)key;
+ SMMUDevice *target = (SMMUDevice *)user_data;
+
+ if (config_key->sdev != target) {
+ return false;
+ }
+ trace_smmu_config_cache_inv(smmu_get_sid(target));
+ return true;
+}
+
+void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev)
+{
+ g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sdev, sdev);
+}
+
void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
uint8_t tg, uint64_t num_pages, uint8_t ttl)
{
@@ -978,7 +1017,9 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
error_propagate(errp, local_err);
return;
}
- s->configs = g_hash_table_new_full(NULL, NULL, NULL, g_free);
+ s->configs = g_hash_table_new_full(smmu_config_key_hash,
+ smmu_config_key_equal,
+ g_free, g_free);
s->iotlb = g_hash_table_new_full(smmu_iotlb_key_hash, smmu_iotlb_key_equal,
g_free, g_free);
s->smmu_pcibus_by_busptr = g_hash_table_new(NULL, NULL);
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index d011357253e..aa1a95a0093 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -904,10 +904,11 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
*
* @sdev: SMMUDevice handle
* @event: output event info
+ * @sec_sid: StreamID Security state
*
* The configuration cache contains data resulting from both STE and CD
* decoding under the form of an SMMUTransCfg struct. The hash table is indexed
- * by the SMMUDevice handle.
+ * by a composite key of the SMMUDevice and the sec_sid.
*/
static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event,
SMMUSecSID sec_sid)
@@ -915,8 +916,9 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event,
SMMUv3State *s = sdev->smmu;
SMMUState *bc = &s->smmu_state;
SMMUTransCfg *cfg;
+ SMMUConfigKey lookup_key = smmu_get_config_key(sdev, sec_sid);
- cfg = g_hash_table_lookup(bc->configs, sdev);
+ cfg = g_hash_table_lookup(bc->configs, &lookup_key);
if (cfg) {
sdev->cfg_cache_hits++;
trace_smmuv3_config_cache_hit(smmu_get_sid(sdev),
@@ -940,7 +942,9 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event,
g_assert(cfg->as && cfg->ns_as);
if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
- g_hash_table_insert(bc->configs, sdev, cfg);
+ SMMUConfigKey *persistent_key = g_new(SMMUConfigKey, 1);
+ *persistent_key = lookup_key;
+ g_hash_table_insert(bc->configs, persistent_key, cfg);
} else {
g_free(cfg);
cfg = NULL;
@@ -954,8 +958,7 @@ static void smmuv3_flush_config(SMMUDevice *sdev)
SMMUv3State *s = sdev->smmu;
SMMUState *bc = &s->smmu_state;
- trace_smmu_config_cache_inv(smmu_get_sid(sdev));
- g_hash_table_remove(bc->configs, sdev);
+ smmu_configs_inv_sdev(bc, sdev);
}
/* Do translation with TLB lookup. */
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index 7944e8d1b64..9e44c9f7710 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -162,6 +162,11 @@ typedef struct SMMUIOTLBKey {
uint8_t level;
} SMMUIOTLBKey;
+typedef struct SMMUConfigKey {
+ SMMUDevice *sdev;
+ SMMUSecSID sec_sid;
+} SMMUConfigKey;
+
typedef struct SMMUSIDRange {
uint32_t start;
uint32_t end;
@@ -250,6 +255,7 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *entry);
SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
uint8_t tg, uint8_t level);
+SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID sec_sid);
void smmu_iotlb_inv_all(SMMUState *s);
void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid);
void smmu_iotlb_inv_vmid(SMMUState *s, int vmid);
@@ -259,6 +265,7 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
uint64_t num_pages, uint8_t ttl);
void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range);
+void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev);
/* Unmap the range of all the notifiers registered to any IOMMU mr */
void smmu_inv_notifiers_all(SMMUState *s);
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 10/31] hw/arm/smmu-common: Key configuration cache on SMMUDevice and SEC_SID
2026-02-21 10:14 ` [RFC v4 10/31] hw/arm/smmu-common: Key configuration cache on SMMUDevice and SEC_SID Tao Tang
@ 2026-02-25 21:01 ` Pierrick Bouvier
2026-03-02 16:54 ` Eric Auger
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:01 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:14 AM, Tao Tang wrote:
> Adapt the configuration cache to support multiple security states by
> introducing a composite key, SMMUConfigKey. This key combines the
> SMMUDevice with SEC_SID, preventing aliasing between Secure and
> Non-secure configurations for the same device, also the future Realm and
> Root configurations.
>
> The cache lookup, insertion, and invalidation mechanisms are updated
> to use this new keying infrastructure. This change is critical for
> ensuring correct translation when a device is active in more than one
> security world.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Link: https://lore.kernel.org/qemu-devel/a9a840a6-c65f-4352-9a49-ddd1b5483f43@redhat.com/
> ---
> hw/arm/smmu-common.c | 45 ++++++++++++++++++++++++++++++++++--
> hw/arm/smmuv3.c | 13 +++++++----
> include/hw/arm/smmu-common.h | 7 ++++++
> 3 files changed, 58 insertions(+), 7 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 10/31] hw/arm/smmu-common: Key configuration cache on SMMUDevice and SEC_SID
2026-02-21 10:14 ` [RFC v4 10/31] hw/arm/smmu-common: Key configuration cache on SMMUDevice and SEC_SID Tao Tang
2026-02-25 21:01 ` Pierrick Bouvier
@ 2026-03-02 16:54 ` Eric Auger
2026-03-05 13:42 ` Tao Tang
1 sibling, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-02 16:54 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi Tao,
On 2/21/26 11:14 AM, Tao Tang wrote:
> Adapt the configuration cache to support multiple security states by
> introducing a composite key, SMMUConfigKey. This key combines the
> SMMUDevice with SEC_SID, preventing aliasing between Secure and
> Non-secure configurations for the same device, also the future Realm and
> Root configurations.
Looking at 27/31, the sec_sid of a device looks rather static, set by a
property. However here you mention risk of aliasing between non secure
and secure for a given sdev
Please could you clarify?
Thanks
Eric
>
> The cache lookup, insertion, and invalidation mechanisms are updated
> to use this new keying infrastructure. This change is critical for
> ensuring correct translation when a device is active in more than one
> security world.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
> Link: https://lore.kernel.org/qemu-devel/a9a840a6-c65f-4352-9a49-ddd1b5483f43@redhat.com/
> ---
> hw/arm/smmu-common.c | 45 ++++++++++++++++++++++++++++++++++--
> hw/arm/smmuv3.c | 13 +++++++----
> include/hw/arm/smmu-common.h | 7 ++++++
> 3 files changed, 58 insertions(+), 7 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index b320aec8c60..a732303b28b 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -30,6 +30,26 @@
> #include "hw/arm/smmu-common.h"
> #include "smmu-internal.h"
>
> +/* Configuration Cache Management */
> +static guint smmu_config_key_hash(gconstpointer key)
> +{
> + const SMMUConfigKey *k = key;
> + return g_direct_hash(k->sdev) ^ (guint)k->sec_sid;
> +}
> +
> +static gboolean smmu_config_key_equal(gconstpointer a, gconstpointer b)
> +{
> + const SMMUConfigKey *ka = a;
> + const SMMUConfigKey *kb = b;
> + return ka->sdev == kb->sdev && ka->sec_sid == kb->sec_sid;
> +}
> +
> +SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID sec_sid)
> +{
> + SMMUConfigKey key = {.sdev = sdev, .sec_sid = sec_sid};
> + return key;
> +}
> +
> ARMSecuritySpace smmu_get_security_space(SMMUSecSID sec_sid)
> {
> switch (sec_sid) {
> @@ -265,7 +285,8 @@ static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
> static gboolean
> smmu_hash_remove_by_sid_range(gpointer key, gpointer value, gpointer user_data)
> {
> - SMMUDevice *sdev = (SMMUDevice *)key;
> + SMMUConfigKey *config_key = (SMMUConfigKey *)key;
> + SMMUDevice *sdev = config_key->sdev;
> uint32_t sid = smmu_get_sid(sdev);
> SMMUSIDRange *sid_range = (SMMUSIDRange *)user_data;
>
> @@ -283,6 +304,24 @@ void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range)
> &sid_range);
> }
>
> +static gboolean smmu_hash_remove_by_sdev(gpointer key, gpointer value,
> + gpointer user_data)
> +{
> + SMMUConfigKey *config_key = (SMMUConfigKey *)key;
> + SMMUDevice *target = (SMMUDevice *)user_data;
> +
> + if (config_key->sdev != target) {
> + return false;
> + }
> + trace_smmu_config_cache_inv(smmu_get_sid(target));
> + return true;
> +}
> +
> +void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev)
> +{
> + g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sdev, sdev);
> +}
> +
> void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> uint8_t tg, uint64_t num_pages, uint8_t ttl)
> {
> @@ -978,7 +1017,9 @@ static void smmu_base_realize(DeviceState *dev, Error **errp)
> error_propagate(errp, local_err);
> return;
> }
> - s->configs = g_hash_table_new_full(NULL, NULL, NULL, g_free);
> + s->configs = g_hash_table_new_full(smmu_config_key_hash,
> + smmu_config_key_equal,
> + g_free, g_free);
> s->iotlb = g_hash_table_new_full(smmu_iotlb_key_hash, smmu_iotlb_key_equal,
> g_free, g_free);
> s->smmu_pcibus_by_busptr = g_hash_table_new(NULL, NULL);
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index d011357253e..aa1a95a0093 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -904,10 +904,11 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
> *
> * @sdev: SMMUDevice handle
> * @event: output event info
> + * @sec_sid: StreamID Security state
> *
> * The configuration cache contains data resulting from both STE and CD
> * decoding under the form of an SMMUTransCfg struct. The hash table is indexed
> - * by the SMMUDevice handle.
> + * by a composite key of the SMMUDevice and the sec_sid.
> */
> static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event,
> SMMUSecSID sec_sid)
> @@ -915,8 +916,9 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event,
> SMMUv3State *s = sdev->smmu;
> SMMUState *bc = &s->smmu_state;
> SMMUTransCfg *cfg;
> + SMMUConfigKey lookup_key = smmu_get_config_key(sdev, sec_sid);
>
> - cfg = g_hash_table_lookup(bc->configs, sdev);
> + cfg = g_hash_table_lookup(bc->configs, &lookup_key);
> if (cfg) {
> sdev->cfg_cache_hits++;
> trace_smmuv3_config_cache_hit(smmu_get_sid(sdev),
> @@ -940,7 +942,9 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event,
> g_assert(cfg->as && cfg->ns_as);
>
> if (!smmuv3_decode_config(&sdev->iommu, cfg, event)) {
> - g_hash_table_insert(bc->configs, sdev, cfg);
> + SMMUConfigKey *persistent_key = g_new(SMMUConfigKey, 1);
> + *persistent_key = lookup_key;
> + g_hash_table_insert(bc->configs, persistent_key, cfg);
> } else {
> g_free(cfg);
> cfg = NULL;
> @@ -954,8 +958,7 @@ static void smmuv3_flush_config(SMMUDevice *sdev)
> SMMUv3State *s = sdev->smmu;
> SMMUState *bc = &s->smmu_state;
>
> - trace_smmu_config_cache_inv(smmu_get_sid(sdev));
> - g_hash_table_remove(bc->configs, sdev);
> + smmu_configs_inv_sdev(bc, sdev);
> }
>
> /* Do translation with TLB lookup. */
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index 7944e8d1b64..9e44c9f7710 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -162,6 +162,11 @@ typedef struct SMMUIOTLBKey {
> uint8_t level;
> } SMMUIOTLBKey;
>
> +typedef struct SMMUConfigKey {
> + SMMUDevice *sdev;
> + SMMUSecSID sec_sid;
> +} SMMUConfigKey;
> +
> typedef struct SMMUSIDRange {
> uint32_t start;
> uint32_t end;
> @@ -250,6 +255,7 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *entry);
> SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> uint8_t tg, uint8_t level);
> +SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID sec_sid);
> void smmu_iotlb_inv_all(SMMUState *s);
> void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid);
> void smmu_iotlb_inv_vmid(SMMUState *s, int vmid);
> @@ -259,6 +265,7 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
> uint64_t num_pages, uint8_t ttl);
> void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range);
> +void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev);
> /* Unmap the range of all the notifiers registered to any IOMMU mr */
> void smmu_inv_notifiers_all(SMMUState *s);
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 10/31] hw/arm/smmu-common: Key configuration cache on SMMUDevice and SEC_SID
2026-03-02 16:54 ` Eric Auger
@ 2026-03-05 13:42 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-05 13:42 UTC (permalink / raw)
To: eric.auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi Eric,
On 2026/3/3 00:54, Eric Auger wrote:
> Hi Tao,
>
> On 2/21/26 11:14 AM, Tao Tang wrote:
>> Adapt the configuration cache to support multiple security states by
>> introducing a composite key, SMMUConfigKey. This key combines the
>> SMMUDevice with SEC_SID, preventing aliasing between Secure and
>> Non-secure configurations for the same device, also the future Realm and
>> Root configurations.
> Looking at 27/31, the sec_sid of a device looks rather static, set by a
> property. However here you mention risk of aliasing between non secure
> and secure for a given sdev
>
> Please could you clarify?
You’re right. In the current RFC the PCI sec-sid is effectively static,
via a device property, so a given sdev does not dynamically switch
between Secure and Non-secure at runtime.
What I meant in this commit was not that this series already implements
such dynamic switching. My intent with keying the cache by (SMMUDevice,
SEC_SID) was to make the cache identity reflect the full security
context of the translation/configuration, rather than implicitly
depending on today’s PCI-side representation.
So for this RFC, the practical effect is mainly to keep the SMMU
internal cache model aligned with the architectural security context,
while avoiding baking the current static PCI representation into the
cache design.
The commit message wording there was too broad, especially the “active
in more than one security world” part. I’ll tighten that in the next
revision.
Thanks,
Tao
>
> Thanks
>
> Eric
>> The cache lookup, insertion, and invalidation mechanisms are updated
>> to use this new keying infrastructure. This change is critical for
>> ensuring correct translation when a device is active in more than one
>> security world.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>> Link: https://lore.kernel.org/qemu-devel/a9a840a6-c65f-4352-9a49-ddd1b5483f43@redhat.com/
>> ---
>> hw/arm/smmu-common.c | 45 ++++++++++++++++++++++++++++++++++--
>> hw/arm/smmuv3.c | 13 +++++++----
>> include/hw/arm/smmu-common.h | 7 ++++++
>> 3 files changed, 58 insertions(+), 7 deletions(-)
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 11/31] hw/arm/smmu: Add PTE NS/NSTable helpers
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (9 preceding siblings ...)
2026-02-21 10:14 ` [RFC v4 10/31] hw/arm/smmu-common: Key configuration cache on SMMUDevice and SEC_SID Tao Tang
@ 2026-02-21 10:15 ` Tao Tang
2026-02-25 21:01 ` Pierrick Bouvier
2026-03-02 17:07 ` Eric Auger
2026-02-21 10:16 ` [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info Tao Tang
` (19 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:15 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Add helper macros for NS and NSTable bits and group PTE attribute
accessors for clarity. No functional change beyond the new helpers.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmu-internal.h | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h
index d143d296f34..a0454f720da 100644
--- a/hw/arm/smmu-internal.h
+++ b/hw/arm/smmu-internal.h
@@ -58,16 +58,28 @@
((level == 3) && \
((pte & ARM_LPAE_PTE_TYPE_MASK) == ARM_LPAE_L3_PTE_TYPE_PAGE))
+/* Block & page descriptor attributes */
+/* Non-secure bit */
+#define PTE_NS(pte) \
+ (extract64(pte, 5, 1))
+
/* access permissions */
#define PTE_AP(pte) \
(extract64(pte, 6, 2))
+/* access flag */
+#define PTE_AF(pte) \
+ (extract64(pte, 10, 1))
+
+
+/* Table descriptor attributes */
#define PTE_APTABLE(pte) \
(extract64(pte, 61, 2))
-#define PTE_AF(pte) \
- (extract64(pte, 10, 1))
+#define PTE_NSTABLE(pte) \
+ (extract64(pte, 63, 1))
+
/*
* TODO: At the moment all transactions are considered as privileged (EL1)
* as IOMMU translation callback does not pass user/priv attributes.
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 11/31] hw/arm/smmu: Add PTE NS/NSTable helpers
2026-02-21 10:15 ` [RFC v4 11/31] hw/arm/smmu: Add PTE NS/NSTable helpers Tao Tang
@ 2026-02-25 21:01 ` Pierrick Bouvier
2026-03-02 17:07 ` Eric Auger
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:01 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:15 AM, Tao Tang wrote:
> Add helper macros for NS and NSTable bits and group PTE attribute
> accessors for clarity. No functional change beyond the new helpers.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-internal.h | 16 ++++++++++++++--
> 1 file changed, 14 insertions(+), 2 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 11/31] hw/arm/smmu: Add PTE NS/NSTable helpers
2026-02-21 10:15 ` [RFC v4 11/31] hw/arm/smmu: Add PTE NS/NSTable helpers Tao Tang
2026-02-25 21:01 ` Pierrick Bouvier
@ 2026-03-02 17:07 ` Eric Auger
2026-03-05 13:22 ` Tao Tang
1 sibling, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-02 17:07 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 2/21/26 11:15 AM, Tao Tang wrote:
> Add helper macros for NS and NSTable bits and group PTE attribute
> accessors for clarity. No functional change beyond the new helpers.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-internal.h | 16 ++++++++++++++--
> 1 file changed, 14 insertions(+), 2 deletions(-)
>
> diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h
> index d143d296f34..a0454f720da 100644
> --- a/hw/arm/smmu-internal.h
> +++ b/hw/arm/smmu-internal.h
> @@ -58,16 +58,28 @@
> ((level == 3) && \
> ((pte & ARM_LPAE_PTE_TYPE_MASK) == ARM_LPAE_L3_PTE_TYPE_PAGE))
>
> +/* Block & page descriptor attributes */
Maybe use the spec terminology:
Stage 1 attribute fields in VMSAv8-64 Block and Page descriptors
vs 7 Stage 1 VMSAv8-64 Table descriptor fields
By the way AF belongs to both
> +/* Non-secure bit */
> +#define PTE_NS(pte) \
> + (extract64(pte, 5, 1))
> +
> /* access permissions */
>
> #define PTE_AP(pte) \
> (extract64(pte, 6, 2))
>
> +/* access flag */
> +#define PTE_AF(pte) \
> + (extract64(pte, 10, 1))
> +
> +
> +/* Table descriptor attributes */
> #define PTE_APTABLE(pte) \
> (extract64(pte, 61, 2))
>
> -#define PTE_AF(pte) \
> - (extract64(pte, 10, 1))
> +#define PTE_NSTABLE(pte) \
> + (extract64(pte, 63, 1))
> +
> /*
> * TODO: At the moment all transactions are considered as privileged (EL1)
> * as IOMMU translation callback does not pass user/priv attributes.
Eric
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 11/31] hw/arm/smmu: Add PTE NS/NSTable helpers
2026-03-02 17:07 ` Eric Auger
@ 2026-03-05 13:22 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-05 13:22 UTC (permalink / raw)
To: eric.auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi Eric,
On 2026/3/3 01:07, Eric Auger wrote:
>
> On 2/21/26 11:15 AM, Tao Tang wrote:
>> Add helper macros for NS and NSTable bits and group PTE attribute
>> accessors for clarity. No functional change beyond the new helpers.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmu-internal.h | 16 ++++++++++++++--
>> 1 file changed, 14 insertions(+), 2 deletions(-)
>>
>> diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h
>> index d143d296f34..a0454f720da 100644
>> --- a/hw/arm/smmu-internal.h
>> +++ b/hw/arm/smmu-internal.h
>> @@ -58,16 +58,28 @@
>> ((level == 3) && \
>> ((pte & ARM_LPAE_PTE_TYPE_MASK) == ARM_LPAE_L3_PTE_TYPE_PAGE))
>>
>> +/* Block & page descriptor attributes */
> Maybe use the spec terminology:
> Stage 1 attribute fields in VMSAv8-64 Block and Page descriptors
> vs 7 Stage 1 VMSAv8-64 Table descriptor fields
>
> By the way AF belongs to both
I’ll rework the comments to use the spec terminology and avoid grouping
AF too narrowly under Block/Page wording.
Best regards,
Tao
>
>> +/* Non-secure bit */
>> +#define PTE_NS(pte) \
>> + (extract64(pte, 5, 1))
>> +
>> /* access permissions */
>>
>> #define PTE_AP(pte) \
>> (extract64(pte, 6, 2))
>>
>> +/* access flag */
>> +#define PTE_AF(pte) \
>> + (extract64(pte, 10, 1))
>> +
>> +
>> +/* Table descriptor attributes */
>> #define PTE_APTABLE(pte) \
>> (extract64(pte, 61, 2))
>>
>> -#define PTE_AF(pte) \
>> - (extract64(pte, 10, 1))
>> +#define PTE_NSTABLE(pte) \
>> + (extract64(pte, 63, 1))
>> +
>> /*
>> * TODO: At the moment all transactions are considered as privileged (EL1)
>> * as IOMMU translation callback does not pass user/priv attributes.
> Eric
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (10 preceding siblings ...)
2026-02-21 10:15 ` [RFC v4 11/31] hw/arm/smmu: Add PTE NS/NSTable helpers Tao Tang
@ 2026-02-21 10:16 ` Tao Tang
2026-02-25 21:01 ` Pierrick Bouvier
` (2 more replies)
2026-02-21 10:16 ` [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries Tao Tang
` (18 subsequent siblings)
30 siblings, 3 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:16 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
With NSCFG definitions in place, record the per-table NSCFG bits
in SMMUTransTableInfo during CD decode for later use.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 1 +
include/hw/arm/smmu-common.h | 1 +
2 files changed, 2 insertions(+)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index aa1a95a0093..b8f2fae9a1d 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -838,6 +838,7 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
tt->ttb = CACHED_ENTRY_TO_ADDR(entry, tt->ttb);
}
+ tt->nscfg = i ? CD_NSCFG(cd, 1) : CD_NSCFG(cd, 0);
tt->had = CD_HAD(cd, i);
trace_smmuv3_decode_cd_tt(i, tt->tsz, tt->ttb, tt->granule_sz, tt->had);
}
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index 9e44c9f7710..bd88e599c77 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -83,6 +83,7 @@ typedef struct SMMUTransTableInfo {
uint8_t tsz; /* input range, ie. 2^(64 -tsz)*/
uint8_t granule_sz; /* granule page shift */
bool had; /* hierarchical attribute disable */
+ int nscfg; /* Non-secure attribute of Starting-level TT */
} SMMUTransTableInfo;
typedef struct SMMUTLBEntry {
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info
2026-02-21 10:16 ` [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info Tao Tang
@ 2026-02-25 21:01 ` Pierrick Bouvier
2026-02-27 14:41 ` Mostafa Saleh
2026-03-02 17:18 ` Eric Auger
2 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:01 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:16 AM, Tao Tang wrote:
> With NSCFG definitions in place, record the per-table NSCFG bits
> in SMMUTransTableInfo during CD decode for later use.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 1 +
> include/hw/arm/smmu-common.h | 1 +
> 2 files changed, 2 insertions(+)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info
2026-02-21 10:16 ` [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info Tao Tang
2026-02-25 21:01 ` Pierrick Bouvier
@ 2026-02-27 14:41 ` Mostafa Saleh
2026-03-01 14:21 ` Tao Tang
2026-03-02 17:18 ` Eric Auger
2 siblings, 1 reply; 136+ messages in thread
From: Mostafa Saleh @ 2026-02-27 14:41 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sat, Feb 21, 2026 at 06:16:32PM +0800, Tao Tang wrote:
> With NSCFG definitions in place, record the per-table NSCFG bits
> in SMMUTransTableInfo during CD decode for later use.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
I feel this patch would be better squashed with how it’s used,
but no strong opinion.
Thanks,
Mostafa
> ---
> hw/arm/smmuv3.c | 1 +
> include/hw/arm/smmu-common.h | 1 +
> 2 files changed, 2 insertions(+)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index aa1a95a0093..b8f2fae9a1d 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -838,6 +838,7 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
> tt->ttb = CACHED_ENTRY_TO_ADDR(entry, tt->ttb);
> }
>
> + tt->nscfg = i ? CD_NSCFG(cd, 1) : CD_NSCFG(cd, 0);
> tt->had = CD_HAD(cd, i);
> trace_smmuv3_decode_cd_tt(i, tt->tsz, tt->ttb, tt->granule_sz, tt->had);
> }
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index 9e44c9f7710..bd88e599c77 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -83,6 +83,7 @@ typedef struct SMMUTransTableInfo {
> uint8_t tsz; /* input range, ie. 2^(64 -tsz)*/
> uint8_t granule_sz; /* granule page shift */
> bool had; /* hierarchical attribute disable */
> + int nscfg; /* Non-secure attribute of Starting-level TT */
> } SMMUTransTableInfo;
>
> typedef struct SMMUTLBEntry {
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info
2026-02-27 14:41 ` Mostafa Saleh
@ 2026-03-01 14:21 ` Tao Tang
2026-03-02 10:22 ` Mostafa Saleh
0 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-03-01 14:21 UTC (permalink / raw)
To: Mostafa Saleh
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
Hi Mostafa,
On 2026/2/27 PM10:41, Mostafa Saleh wrote:
> On Sat, Feb 21, 2026 at 06:16:32PM +0800, Tao Tang wrote:
>> With NSCFG definitions in place, record the per-table NSCFG bits
>> in SMMUTransTableInfo during CD decode for later use.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> I feel this patch would be better squashed with how it’s used,
> but no strong opinion.
I split "definition" vs "usage" here because Eric suggested keeping
plumbing changes separate in previous series.
That said, I don’t mind squashing this into "hw/arm/smmu-common:
Implement secure state handling in ptw" in V5, since it’s effectively a
one-liner and will make the series smaller.
> Thanks,
> Mostafa
Best regards,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info
2026-03-01 14:21 ` Tao Tang
@ 2026-03-02 10:22 ` Mostafa Saleh
2026-03-02 17:21 ` Eric Auger
0 siblings, 1 reply; 136+ messages in thread
From: Mostafa Saleh @ 2026-03-02 10:22 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sun, Mar 01, 2026 at 10:21:55PM +0800, Tao Tang wrote:
> Hi Mostafa,
>
> On 2026/2/27 PM10:41, Mostafa Saleh wrote:
> > On Sat, Feb 21, 2026 at 06:16:32PM +0800, Tao Tang wrote:
> > > With NSCFG definitions in place, record the per-table NSCFG bits
> > > in SMMUTransTableInfo during CD decode for later use.
> > >
> > > Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> > I feel this patch would be better squashed with how it’s used,
> > but no strong opinion.
>
>
> I split "definition" vs "usage" here because Eric suggested keeping plumbing
> changes separate in previous series.
>
I don't have a strong opinion, you can keep it, if Eric is ok with it.
I was just looking for ways to keep this series shorter.
Thanks,
Mostafa
>
> That said, I don’t mind squashing this into "hw/arm/smmu-common: Implement
> secure state handling in ptw" in V5, since it’s effectively a one-liner and
> will make the series smaller.
>
>
> > Thanks,
> > Mostafa
>
>
> Best regards,
>
> Tao
>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info
2026-03-02 10:22 ` Mostafa Saleh
@ 2026-03-02 17:21 ` Eric Auger
0 siblings, 0 replies; 136+ messages in thread
From: Eric Auger @ 2026-03-02 17:21 UTC (permalink / raw)
To: Mostafa Saleh, Tao Tang
Cc: Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum, qemu-devel,
qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On 3/2/26 11:22 AM, Mostafa Saleh wrote:
> On Sun, Mar 01, 2026 at 10:21:55PM +0800, Tao Tang wrote:
>> Hi Mostafa,
>>
>> On 2026/2/27 PM10:41, Mostafa Saleh wrote:
>>> On Sat, Feb 21, 2026 at 06:16:32PM +0800, Tao Tang wrote:
>>>> With NSCFG definitions in place, record the per-table NSCFG bits
>>>> in SMMUTransTableInfo during CD decode for later use.
>>>>
>>>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>>> I feel this patch would be better squashed with how it’s used,
>>> but no strong opinion.
>>
>> I split "definition" vs "usage" here because Eric suggested keeping plumbing
>> changes separate in previous series.
>>
> I don't have a strong opinion, you can keep it, if Eric is ok with it.
> I was just looking for ways to keep this series shorter.
No strong opinion either. assuming this nscfg field is used in
subsequent patches, I find it easy to review it separately.
I prefer to have a big series with simple logical and functional changes
(that better fits my mind) rather than a small one with intricate patches.
Thanks
Eric
>
> Thanks,
> Mostafa
>
>> That said, I don’t mind squashing this into "hw/arm/smmu-common: Implement
>> secure state handling in ptw" in V5, since it’s effectively a one-liner and
>> will make the series smaller.
>>
>>
>>> Thanks,
>>> Mostafa
>>
>> Best regards,
>>
>> Tao
>>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info
2026-02-21 10:16 ` [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info Tao Tang
2026-02-25 21:01 ` Pierrick Bouvier
2026-02-27 14:41 ` Mostafa Saleh
@ 2026-03-02 17:18 ` Eric Auger
2 siblings, 0 replies; 136+ messages in thread
From: Eric Auger @ 2026-03-02 17:18 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 2/21/26 11:16 AM, Tao Tang wrote:
> With NSCFG definitions in place, record the per-table NSCFG bits
> in SMMUTransTableInfo during CD decode for later use.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 1 +
> include/hw/arm/smmu-common.h | 1 +
> 2 files changed, 2 insertions(+)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index aa1a95a0093..b8f2fae9a1d 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -838,6 +838,7 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
> tt->ttb = CACHED_ENTRY_TO_ADDR(entry, tt->ttb);
> }
>
> + tt->nscfg = i ? CD_NSCFG(cd, 1) : CD_NSCFG(cd, 0);
tt->nscfg = CD_NSCFG(cd, i)?
Besides
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
> tt->had = CD_HAD(cd, i);
> trace_smmuv3_decode_cd_tt(i, tt->tsz, tt->ttb, tt->granule_sz, tt->had);
> }
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index 9e44c9f7710..bd88e599c77 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -83,6 +83,7 @@ typedef struct SMMUTransTableInfo {
> uint8_t tsz; /* input range, ie. 2^(64 -tsz)*/
> uint8_t granule_sz; /* granule page shift */
> bool had; /* hierarchical attribute disable */
> + int nscfg; /* Non-secure attribute of Starting-level TT */
> } SMMUTransTableInfo;
>
> typedef struct SMMUTLBEntry {
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (11 preceding siblings ...)
2026-02-21 10:16 ` [RFC v4 12/31] hw/arm/smmuv3: Store CD NSCFG in TT info Tao Tang
@ 2026-02-21 10:16 ` Tao Tang
2026-02-25 21:02 ` Pierrick Bouvier
` (2 more replies)
2026-02-21 10:16 ` [RFC v4 14/31] hw/arm/smmu-common: Implement secure state handling in ptw Tao Tang
` (17 subsequent siblings)
30 siblings, 3 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:16 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
This is a non-functional preparation step that adds storage for
resolved security state in SMMUTLBEntry.
Together with the earlier commits that added NSCFG handling and
PTE NS/NSTable helpers, the plumbing is complete and we can now
refactor the PTW flow to handle Secure state.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
include/hw/arm/smmu-common.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index bd88e599c77..b0a02e12fe6 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -91,6 +91,7 @@ typedef struct SMMUTLBEntry {
uint8_t level;
uint8_t granule;
IOMMUAccessFlags parent_perm;
+ SMMUSecSID sec_sid;
} SMMUTLBEntry;
/* Stage-2 configuration. */
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries
2026-02-21 10:16 ` [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries Tao Tang
@ 2026-02-25 21:02 ` Pierrick Bouvier
2026-02-27 14:45 ` Mostafa Saleh
2026-03-02 17:34 ` Eric Auger
2 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:02 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:16 AM, Tao Tang wrote:
> This is a non-functional preparation step that adds storage for
> resolved security state in SMMUTLBEntry.
>
> Together with the earlier commits that added NSCFG handling and
> PTE NS/NSTable helpers, the plumbing is complete and we can now
> refactor the PTW flow to handle Secure state.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> include/hw/arm/smmu-common.h | 1 +
> 1 file changed, 1 insertion(+)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries
2026-02-21 10:16 ` [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries Tao Tang
2026-02-25 21:02 ` Pierrick Bouvier
@ 2026-02-27 14:45 ` Mostafa Saleh
2026-03-01 15:08 ` Tao Tang
2026-03-02 17:34 ` Eric Auger
2 siblings, 1 reply; 136+ messages in thread
From: Mostafa Saleh @ 2026-02-27 14:45 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sat, Feb 21, 2026 at 06:16:40PM +0800, Tao Tang wrote:
> This is a non-functional preparation step that adds storage for
> resolved security state in SMMUTLBEntry.
>
I am not sure about this, when I added stage-2 I re-used the same
TLB instance as it might be used for nesting, and we can have
end-to-end cached entires.
For secure state, I think it’s cleaner to instantiate a new TLB, as
both states can never mix, and in this case we can re-use the same
functions without adding the secure bit in the TLB.
Thanks,
Mostafa
> Together with the earlier commits that added NSCFG handling and
> PTE NS/NSTable helpers, the plumbing is complete and we can now
> refactor the PTW flow to handle Secure state.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> include/hw/arm/smmu-common.h | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index bd88e599c77..b0a02e12fe6 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -91,6 +91,7 @@ typedef struct SMMUTLBEntry {
> uint8_t level;
> uint8_t granule;
> IOMMUAccessFlags parent_perm;
> + SMMUSecSID sec_sid;
> } SMMUTLBEntry;
>
> /* Stage-2 configuration. */
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries
2026-02-27 14:45 ` Mostafa Saleh
@ 2026-03-01 15:08 ` Tao Tang
2026-03-02 10:30 ` Mostafa Saleh
0 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-03-01 15:08 UTC (permalink / raw)
To: Mostafa Saleh
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
Hi Mostafa,
On 2026/2/27 PM10:45, Mostafa Saleh wrote:
> On Sat, Feb 21, 2026 at 06:16:40PM +0800, Tao Tang wrote:
>> This is a non-functional preparation step that adds storage for
>> resolved security state in SMMUTLBEntry.
>>
> I am not sure about this, when I added stage-2 I re-used the same
> TLB instance as it might be used for nesting, and we can have
> end-to-end cached entires.
> For secure state, I think it’s cleaner to instantiate a new TLB, as
> both states can never mix, and in this case we can re-use the same
> functions without adding the secure bit in the TLB.
Thanks for the suggestion.
I agree that keeping separate TLB instances per security state is
cleaner and avoids having to carry a sec_sid tag through every cache path.
The only downside is a bit more plumbing: we’ll need to make sure the
translation/PTW paths always pick the right per-bank TLB (otherwise some
call sites may still default to the NS one). This also means touching
the common layer since smmu-common currently assumes a single s->iotlb.
Although some refactoring work is still needed, I’m happy to follow your
approach and will rework this in V5.
>
> Thanks,
> Mostafa
Best regards,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries
2026-03-01 15:08 ` Tao Tang
@ 2026-03-02 10:30 ` Mostafa Saleh
0 siblings, 0 replies; 136+ messages in thread
From: Mostafa Saleh @ 2026-03-02 10:30 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sun, Mar 1, 2026 at 3:08 PM Tao Tang <tangtao1634@phytium.com.cn> wrote:
>
> Hi Mostafa,
>
> On 2026/2/27 PM10:45, Mostafa Saleh wrote:
> > On Sat, Feb 21, 2026 at 06:16:40PM +0800, Tao Tang wrote:
> >> This is a non-functional preparation step that adds storage for
> >> resolved security state in SMMUTLBEntry.
> >>
> > I am not sure about this, when I added stage-2 I re-used the same
> > TLB instance as it might be used for nesting, and we can have
> > end-to-end cached entires.
> > For secure state, I think it’s cleaner to instantiate a new TLB, as
> > both states can never mix, and in this case we can re-use the same
> > functions without adding the secure bit in the TLB.
>
>
> Thanks for the suggestion.
>
> I agree that keeping separate TLB instances per security state is
> cleaner and avoids having to carry a sec_sid tag through every cache path.
>
> The only downside is a bit more plumbing: we’ll need to make sure the
> translation/PTW paths always pick the right per-bank TLB (otherwise some
> call sites may still default to the NS one). This also means touching
> the common layer since smmu-common currently assumes a single s->iotlb.
>
I see, I will need to think more about this. My initial thought was
that the iotlb seems to be exclusively used in smmu_iotlb_*()
So, I was wondering if we can change those functions to pass the iotlb
as a function argument. We should have enough context from translation
or invalidation paths to pass the correct iotlb instance.
But, I agree, it might not be as simple as I imagine, although I think
that would be cleaner. I will look more into it.
Thanks,
Mostafa
>
> Although some refactoring work is still needed, I’m happy to follow your
> approach and will rework this in V5.
>
>
> >
> > Thanks,
> > Mostafa
>
>
> Best regards,
>
> Tao
>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries
2026-02-21 10:16 ` [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries Tao Tang
2026-02-25 21:02 ` Pierrick Bouvier
2026-02-27 14:45 ` Mostafa Saleh
@ 2026-03-02 17:34 ` Eric Auger
2026-03-05 14:33 ` Tao Tang
2 siblings, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-02 17:34 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 2/21/26 11:16 AM, Tao Tang wrote:
> This is a non-functional preparation step that adds storage for
> resolved security state in SMMUTLBEntry.
Add the "why"in the commit description.
>
> Together with the earlier commits that added NSCFG handling and
> PTE NS/NSTable helpers, the plumbing is complete and we can now
> refactor the PTW flow to handle Secure state.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> include/hw/arm/smmu-common.h | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index bd88e599c77..b0a02e12fe6 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -91,6 +91,7 @@ typedef struct SMMUTLBEntry {
> uint8_t level;
> uint8_t granule;
> IOMMUAccessFlags parent_perm;
> + SMMUSecSID sec_sid;
> } SMMUTLBEntry;
what does it need to be part of the actual entry and not only of the key?
Eric
>
> /* Stage-2 configuration. */
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries
2026-03-02 17:34 ` Eric Auger
@ 2026-03-05 14:33 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-05 14:33 UTC (permalink / raw)
To: eric.auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi Eric,
On 2026/3/3 01:34, Eric Auger wrote:
>
> On 2/21/26 11:16 AM, Tao Tang wrote:
>> This is a non-functional preparation step that adds storage for
>> resolved security state in SMMUTLBEntry.
> Add the "why"in the commit description.
>> Together with the earlier commits that added NSCFG handling and
>> PTE NS/NSTable helpers, the plumbing is complete and we can now
>> refactor the PTW flow to handle Secure state.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> include/hw/arm/smmu-common.h | 1 +
>> 1 file changed, 1 insertion(+)
>>
>> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
>> index bd88e599c77..b0a02e12fe6 100644
>> --- a/include/hw/arm/smmu-common.h
>> +++ b/include/hw/arm/smmu-common.h
>> @@ -91,6 +91,7 @@ typedef struct SMMUTLBEntry {
>> uint8_t level;
>> uint8_t granule;
>> IOMMUAccessFlags parent_perm;
>> + SMMUSecSID sec_sid;
>> } SMMUTLBEntry;
> what does it need to be part of the actual entry and not only of the key?
sec_sid does not need to live in SMMUTLBEntry. After rechecking the
code, SMMUTLBEntry.sec_sid is only consumed in:
smmu_ptw_64_s1
if (current_ns) {
tlbe->sec_sid = SMMU_SEC_SID_NS;
} else {
tlbe->sec_sid = PTE_NS(pte) ? SMMU_SEC_SID_NS : SMMU_SEC_SID_S;
}
tlbe->entry.target_as = (tlbe->sec_sid == SMMU_SEC_SID_S)
? &bs->secure_memory_as : &bs->memory_as;
tlbe->entry.translated_addr = gpa;
and smmu_ptw_64_s2:
tlbe->sec_sid = SMMU_SEC_SID_NS;
tlbe->entry.target_as = cfg->ns_as;
tlbe->entry.translated_addr = gpa;
to get the target_as. So keeping it in the cached entry is unnecessary
if we use a local sec_sid instead.
I’ll drop this field and keep the security-state handling local to the
walk instead. If we later need it for TLB disambiguation, it belongs in
the lookup key rather than the entry payload.
Thanks for the catch.
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 14/31] hw/arm/smmu-common: Implement secure state handling in ptw
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (12 preceding siblings ...)
2026-02-21 10:16 ` [RFC v4 13/31] hw/arm/smmu-common: Add sec_sid field to TLB entries Tao Tang
@ 2026-02-21 10:16 ` Tao Tang
2026-02-25 21:12 ` Pierrick Bouvier
2026-03-03 9:41 ` Eric Auger
2026-02-21 10:16 ` [RFC v4 15/31] hw/arm/smmuv3: Tag IOTLB cache keys with SEC_SID Tao Tang
` (16 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:16 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Enhance the page table walker to correctly handle secure and non-secure
memory accesses. This change introduces logic to select the appropriate
address space and enforce architectural security policies during walks.
The page table walker now correctly processes Secure Stage 1
translations. Key changes include:
- The get_pte function now uses the security context to fetch table
entries from either the Secure or Non-secure address space.
- The stage 1 walker tracks the security state, respecting the NSCFG
and NSTable attributes. It correctly handles the hierarchical security
model: if a table descriptor in a secure walk has NSTable=1, all
subsequent lookups for that walk are forced into the Non-secure space.
This is a one-way transition, as specified by the architecture.
- The final TLB entry is tagged with the correct output address space,
ensuring proper memory isolation.
Note: We do not yet support secure stage 2 translations. So ns_as member
in SMMUTransCfg is used to cache non-secure AS instead of refactoring
smmu_ptw_64_s2 to pass SMMUState context.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmu-common.c | 50 ++++++++++++++++++++++++++++++++++++++++----
hw/arm/smmuv3.c | 1 +
2 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index a732303b28b..84e71df6767 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -406,15 +406,16 @@ void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
/**
* get_pte - Get the content of a page table entry located at
* @base_addr[@index]
+ * @as: AddressSpace to read from
*/
static int get_pte(dma_addr_t baseaddr, uint32_t index, uint64_t *pte,
- SMMUPTWEventInfo *info)
+ SMMUPTWEventInfo *info, AddressSpace *as, MemTxAttrs attrs)
{
int ret;
dma_addr_t addr = baseaddr + index * sizeof(*pte);
/* TODO: guarantee 64-bit single-copy atomicity */
- ret = ldq_le_dma(&address_space_memory, addr, pte, MEMTXATTRS_UNSPECIFIED);
+ ret = ldq_le_dma(as, addr, pte, attrs);
if (ret != MEMTX_OK) {
info->type = SMMU_PTW_ERR_WALK_EABT;
@@ -538,6 +539,9 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
SMMUStage stage = cfg->stage;
SMMUTransTableInfo *tt = select_tt(cfg, iova);
uint8_t level, granule_sz, inputsize, stride;
+ int nscfg, current_ns, new_nstable;
+ bool sid_is_ns = cfg->sec_sid == SMMU_SEC_SID_NS;
+ bool forced_ns = false; /* Once true, NSTable is ignored */
if (!tt || tt->disabled) {
info->type = SMMU_PTW_ERR_TRANSLATION;
@@ -552,6 +556,8 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
baseaddr = extract64(tt->ttb, 0, cfg->oas);
baseaddr &= ~indexmask;
+ nscfg = tt->nscfg;
+ forced_ns = sid_is_ns || nscfg;
while (level < VMSA_LEVELS) {
uint64_t subpage_size = 1ULL << level_shift(level, granule_sz);
@@ -560,8 +566,17 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
uint64_t pte, gpa;
dma_addr_t pte_addr = baseaddr + offset * sizeof(pte);
uint8_t ap;
+ AddressSpace *pte_as;
+ MemTxAttrs pte_attrs;
- if (get_pte(baseaddr, offset, &pte, info)) {
+ /*
+ * Start in NS for Non-secure streams or CD.NSCFGx == 1.
+ * Once walk is in NS, NSTable is ignored on subsequent levels.
+ */
+ current_ns = forced_ns || nscfg;
+ pte_as = current_ns ? &bs->memory_as : &bs->secure_memory_as;
+ pte_attrs = current_ns ? MEMTXATTRS_UNSPECIFIED : cfg->txattrs;
+ if (get_pte(baseaddr, offset, &pte, info, pte_as, pte_attrs)) {
goto error;
}
trace_smmu_ptw_level(stage, level, iova, subpage_size,
@@ -586,6 +601,23 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
goto error;
}
}
+
+ /*
+ * NSTable can switch the walk to NS only while the current walk
+ * level is Secure. Once switched to NS, NSTable is ignored according
+ * to hierarchical control of Secure/Non-secure accesses:
+ * (IHI 0070G.b)13.4.1 Stage 1 page permissions and
+ * (DDI 0487H.a)D8.4.2 Control of Secure or Non-secure memory access
+ */
+ if (!forced_ns) {
+ new_nstable = PTE_NSTABLE(pte);
+ if (new_nstable) {
+ forced_ns = true;
+ nscfg = 1;
+ } else {
+ nscfg = 0;
+ }
+ }
level++;
continue;
} else if (is_page_pte(pte, level)) {
@@ -628,6 +660,13 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
goto error;
}
+ if (current_ns) {
+ tlbe->sec_sid = SMMU_SEC_SID_NS;
+ } else {
+ tlbe->sec_sid = PTE_NS(pte) ? SMMU_SEC_SID_NS : SMMU_SEC_SID_S;
+ }
+ tlbe->entry.target_as = (tlbe->sec_sid == SMMU_SEC_SID_S)
+ ? &bs->secure_memory_as : &bs->memory_as;
tlbe->entry.translated_addr = gpa;
tlbe->entry.iova = iova & ~mask;
tlbe->entry.addr_mask = mask;
@@ -697,7 +736,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
dma_addr_t pte_addr = baseaddr + offset * sizeof(pte);
uint8_t s2ap;
- if (get_pte(baseaddr, offset, &pte, info)) {
+ if (get_pte(baseaddr, offset, &pte, info, cfg->ns_as,
+ MEMTXATTRS_UNSPECIFIED)) {
goto error;
}
trace_smmu_ptw_level(stage, level, ipa, subpage_size,
@@ -750,6 +790,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
goto error_ipa;
}
+ tlbe->sec_sid = SMMU_SEC_SID_NS;
+ tlbe->entry.target_as = cfg->ns_as;
tlbe->entry.translated_addr = gpa;
tlbe->entry.iova = ipa & ~mask;
tlbe->entry.addr_mask = mask;
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index b8f2fae9a1d..504161ce06d 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1147,6 +1147,7 @@ epilogue:
switch (status) {
case SMMU_TRANS_SUCCESS:
entry.perm = cached_entry->entry.perm;
+ entry.target_as = cached_entry->entry.target_as;
entry.translated_addr = CACHED_ENTRY_TO_ADDR(cached_entry, addr);
entry.addr_mask = cached_entry->entry.addr_mask;
trace_smmuv3_translate_success(mr->parent_obj.name, sid, addr,
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 14/31] hw/arm/smmu-common: Implement secure state handling in ptw
2026-02-21 10:16 ` [RFC v4 14/31] hw/arm/smmu-common: Implement secure state handling in ptw Tao Tang
@ 2026-02-25 21:12 ` Pierrick Bouvier
2026-02-28 14:07 ` Tao Tang
2026-03-03 9:41 ` Eric Auger
1 sibling, 1 reply; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:12 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:16 AM, Tao Tang wrote:
> Enhance the page table walker to correctly handle secure and non-secure
> memory accesses. This change introduces logic to select the appropriate
> address space and enforce architectural security policies during walks.
>
> The page table walker now correctly processes Secure Stage 1
> translations. Key changes include:
>
> - The get_pte function now uses the security context to fetch table
> entries from either the Secure or Non-secure address space.
>
> - The stage 1 walker tracks the security state, respecting the NSCFG
> and NSTable attributes. It correctly handles the hierarchical security
> model: if a table descriptor in a secure walk has NSTable=1, all
> subsequent lookups for that walk are forced into the Non-secure space.
> This is a one-way transition, as specified by the architecture.
>
> - The final TLB entry is tagged with the correct output address space,
> ensuring proper memory isolation.
>
> Note: We do not yet support secure stage 2 translations. So ns_as member
> in SMMUTransCfg is used to cache non-secure AS instead of refactoring
> smmu_ptw_64_s2 to pass SMMUState context.
>
Does it requires so much refactor it's better to keep it as a field in
cfg instead?
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 50 ++++++++++++++++++++++++++++++++++++++++----
> hw/arm/smmuv3.c | 1 +
> 2 files changed, 47 insertions(+), 4 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index a732303b28b..84e71df6767 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -406,15 +406,16 @@ void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
> /**
> * get_pte - Get the content of a page table entry located at
> * @base_addr[@index]
> + * @as: AddressSpace to read from
> */
> static int get_pte(dma_addr_t baseaddr, uint32_t index, uint64_t *pte,
> - SMMUPTWEventInfo *info)
> + SMMUPTWEventInfo *info, AddressSpace *as, MemTxAttrs attrs)
> {
> int ret;
> dma_addr_t addr = baseaddr + index * sizeof(*pte);
>
> /* TODO: guarantee 64-bit single-copy atomicity */
> - ret = ldq_le_dma(&address_space_memory, addr, pte, MEMTXATTRS_UNSPECIFIED);
> + ret = ldq_le_dma(as, addr, pte, attrs);
>
> if (ret != MEMTX_OK) {
> info->type = SMMU_PTW_ERR_WALK_EABT;
> @@ -538,6 +539,9 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
> SMMUStage stage = cfg->stage;
> SMMUTransTableInfo *tt = select_tt(cfg, iova);
> uint8_t level, granule_sz, inputsize, stride;
> + int nscfg, current_ns, new_nstable;
> + bool sid_is_ns = cfg->sec_sid == SMMU_SEC_SID_NS;
> + bool forced_ns = false; /* Once true, NSTable is ignored */
>
> if (!tt || tt->disabled) {
> info->type = SMMU_PTW_ERR_TRANSLATION;
> @@ -552,6 +556,8 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
>
> baseaddr = extract64(tt->ttb, 0, cfg->oas);
> baseaddr &= ~indexmask;
> + nscfg = tt->nscfg;
> + forced_ns = sid_is_ns || nscfg;
>
> while (level < VMSA_LEVELS) {
> uint64_t subpage_size = 1ULL << level_shift(level, granule_sz);
> @@ -560,8 +566,17 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
> uint64_t pte, gpa;
> dma_addr_t pte_addr = baseaddr + offset * sizeof(pte);
> uint8_t ap;
> + AddressSpace *pte_as;
> + MemTxAttrs pte_attrs;
>
> - if (get_pte(baseaddr, offset, &pte, info)) {
> + /*
> + * Start in NS for Non-secure streams or CD.NSCFGx == 1.
> + * Once walk is in NS, NSTable is ignored on subsequent levels.
> + */
> + current_ns = forced_ns || nscfg;
> + pte_as = current_ns ? &bs->memory_as : &bs->secure_memory_as;
> + pte_attrs = current_ns ? MEMTXATTRS_UNSPECIFIED : cfg->txattrs;
> + if (get_pte(baseaddr, offset, &pte, info, pte_as, pte_attrs)) {
> goto error;
> }
> trace_smmu_ptw_level(stage, level, iova, subpage_size,
> @@ -586,6 +601,23 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
> goto error;
> }
> }
> +
> + /*
> + * NSTable can switch the walk to NS only while the current walk
> + * level is Secure. Once switched to NS, NSTable is ignored according
> + * to hierarchical control of Secure/Non-secure accesses:
> + * (IHI 0070G.b)13.4.1 Stage 1 page permissions and
> + * (DDI 0487H.a)D8.4.2 Control of Secure or Non-secure memory access
> + */
> + if (!forced_ns) {
> + new_nstable = PTE_NSTABLE(pte);
> + if (new_nstable) {
> + forced_ns = true;
> + nscfg = 1;
> + } else {
> + nscfg = 0;
> + }
> + }
> level++;
> continue;
> } else if (is_page_pte(pte, level)) {
> @@ -628,6 +660,13 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
> goto error;
> }
>
> + if (current_ns) {
> + tlbe->sec_sid = SMMU_SEC_SID_NS;
> + } else {
> + tlbe->sec_sid = PTE_NS(pte) ? SMMU_SEC_SID_NS : SMMU_SEC_SID_S;
> + }
> + tlbe->entry.target_as = (tlbe->sec_sid == SMMU_SEC_SID_S)
> + ? &bs->secure_memory_as : &bs->memory_as;
Having SMMUState passed there would allow to reuse smmu_get_address_space.
> tlbe->entry.translated_addr = gpa;
> tlbe->entry.iova = iova & ~mask;
> tlbe->entry.addr_mask = mask;
> @@ -697,7 +736,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> dma_addr_t pte_addr = baseaddr + offset * sizeof(pte);
> uint8_t s2ap;
>
> - if (get_pte(baseaddr, offset, &pte, info)) {
> + if (get_pte(baseaddr, offset, &pte, info, cfg->ns_as,
> + MEMTXATTRS_UNSPECIFIED)) {
> goto error;
> }
> trace_smmu_ptw_level(stage, level, ipa, subpage_size,
> @@ -750,6 +790,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> goto error_ipa;
> }
>
> + tlbe->sec_sid = SMMU_SEC_SID_NS;
> + tlbe->entry.target_as = cfg->ns_as;
> tlbe->entry.translated_addr = gpa;
> tlbe->entry.iova = ipa & ~mask;
> tlbe->entry.addr_mask = mask;
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index b8f2fae9a1d..504161ce06d 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1147,6 +1147,7 @@ epilogue:
> switch (status) {
> case SMMU_TRANS_SUCCESS:
> entry.perm = cached_entry->entry.perm;
> + entry.target_as = cached_entry->entry.target_as;
> entry.translated_addr = CACHED_ENTRY_TO_ADDR(cached_entry, addr);
> entry.addr_mask = cached_entry->entry.addr_mask;
> trace_smmuv3_translate_success(mr->parent_obj.name, sid, addr,
Overall looks good, and my remarks above are more suggestions than
blocking comments.
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 14/31] hw/arm/smmu-common: Implement secure state handling in ptw
2026-02-25 21:12 ` Pierrick Bouvier
@ 2026-02-28 14:07 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-28 14:07 UTC (permalink / raw)
To: Pierrick Bouvier, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
Hi Pierrick,
On 2026/2/26 05:12, Pierrick Bouvier wrote:
> On 2/21/26 2:16 AM, Tao Tang wrote:
>> Enhance the page table walker to correctly handle secure and non-secure
>> memory accesses. This change introduces logic to select the appropriate
>> address space and enforce architectural security policies during walks.
>>
>> The page table walker now correctly processes Secure Stage 1
>> translations. Key changes include:
>>
>> - The get_pte function now uses the security context to fetch table
>> entries from either the Secure or Non-secure address space.
>>
>> - The stage 1 walker tracks the security state, respecting the NSCFG
>> and NSTable attributes. It correctly handles the hierarchical security
>> model: if a table descriptor in a secure walk has NSTable=1, all
>> subsequent lookups for that walk are forced into the Non-secure space.
>> This is a one-way transition, as specified by the architecture.
>>
>> - The final TLB entry is tagged with the correct output address space,
>> ensuring proper memory isolation.
>>
>> Note: We do not yet support secure stage 2 translations. So ns_as member
>> in SMMUTransCfg is used to cache non-secure AS instead of refactoring
>> smmu_ptw_64_s2 to pass SMMUState context.
>>
>
> Does it requires so much refactor it's better to keep it as a field in
> cfg instead?
As this has already been discussed earlier in the thread, I’ll wait for
Eric’s final confirmation. Once we have that, I’ll incorporate the
necessary refactoring in v5.
>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmu-common.c | 50 ++++++++++++++++++++++++++++++++++++++++----
>> hw/arm/smmuv3.c | 1 +
>> 2 files changed, 47 insertions(+), 4 deletions(-)
>>
>> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
>> index a732303b28b..84e71df6767 100644
>> --- a/hw/arm/smmu-common.c
>> +++ b/hw/arm/smmu-common.c
>> @@ -406,15 +406,16 @@ void smmu_iotlb_inv_vmid_s1(SMMUState *s, int
>> vmid)
>> /**
>> * get_pte - Get the content of a page table entry located at
>> * @base_addr[@index]
>> + * @as: AddressSpace to read from
>> */
>> static int get_pte(dma_addr_t baseaddr, uint32_t index, uint64_t *pte,
>> - SMMUPTWEventInfo *info)
>> + SMMUPTWEventInfo *info, AddressSpace *as,
>> MemTxAttrs attrs)
>> {
>> int ret;
>> dma_addr_t addr = baseaddr + index * sizeof(*pte);
>> /* TODO: guarantee 64-bit single-copy atomicity */
>> - ret = ldq_le_dma(&address_space_memory, addr, pte,
>> MEMTXATTRS_UNSPECIFIED);
>> + ret = ldq_le_dma(as, addr, pte, attrs);
>> if (ret != MEMTX_OK) {
>> info->type = SMMU_PTW_ERR_WALK_EABT;
>> @@ -538,6 +539,9 @@ static int smmu_ptw_64_s1(SMMUState *bs,
>> SMMUTransCfg *cfg,
>> SMMUStage stage = cfg->stage;
>> SMMUTransTableInfo *tt = select_tt(cfg, iova);
>> uint8_t level, granule_sz, inputsize, stride;
>> + int nscfg, current_ns, new_nstable;
>> + bool sid_is_ns = cfg->sec_sid == SMMU_SEC_SID_NS;
>> + bool forced_ns = false; /* Once true, NSTable is ignored */
>> if (!tt || tt->disabled) {
>> info->type = SMMU_PTW_ERR_TRANSLATION;
>> @@ -552,6 +556,8 @@ static int smmu_ptw_64_s1(SMMUState *bs,
>> SMMUTransCfg *cfg,
>> baseaddr = extract64(tt->ttb, 0, cfg->oas);
>> baseaddr &= ~indexmask;
>> + nscfg = tt->nscfg;
>> + forced_ns = sid_is_ns || nscfg;
>> while (level < VMSA_LEVELS) {
>> uint64_t subpage_size = 1ULL << level_shift(level,
>> granule_sz);
>> @@ -560,8 +566,17 @@ static int smmu_ptw_64_s1(SMMUState *bs,
>> SMMUTransCfg *cfg,
>> uint64_t pte, gpa;
>> dma_addr_t pte_addr = baseaddr + offset * sizeof(pte);
>> uint8_t ap;
>> + AddressSpace *pte_as;
>> + MemTxAttrs pte_attrs;
>> - if (get_pte(baseaddr, offset, &pte, info)) {
>> + /*
>> + * Start in NS for Non-secure streams or CD.NSCFGx == 1.
>> + * Once walk is in NS, NSTable is ignored on subsequent levels.
>> + */
>> + current_ns = forced_ns || nscfg;
>> + pte_as = current_ns ? &bs->memory_as : &bs->secure_memory_as;
>> + pte_attrs = current_ns ? MEMTXATTRS_UNSPECIFIED : cfg->txattrs;
>> + if (get_pte(baseaddr, offset, &pte, info, pte_as, pte_attrs)) {
>> goto error;
>> }
>> trace_smmu_ptw_level(stage, level, iova, subpage_size,
>> @@ -586,6 +601,23 @@ static int smmu_ptw_64_s1(SMMUState *bs,
>> SMMUTransCfg *cfg,
>> goto error;
>> }
>> }
>> +
>> + /*
>> + * NSTable can switch the walk to NS only while the
>> current walk
>> + * level is Secure. Once switched to NS, NSTable is
>> ignored according
>> + * to hierarchical control of Secure/Non-secure accesses:
>> + * (IHI 0070G.b)13.4.1 Stage 1 page permissions and
>> + * (DDI 0487H.a)D8.4.2 Control of Secure or Non-secure
>> memory access
>> + */
>> + if (!forced_ns) {
>> + new_nstable = PTE_NSTABLE(pte);
>> + if (new_nstable) {
>> + forced_ns = true;
>> + nscfg = 1;
>> + } else {
>> + nscfg = 0;
>> + }
>> + }
>> level++;
>> continue;
>> } else if (is_page_pte(pte, level)) {
>> @@ -628,6 +660,13 @@ static int smmu_ptw_64_s1(SMMUState *bs,
>> SMMUTransCfg *cfg,
>> goto error;
>> }
>> + if (current_ns) {
>> + tlbe->sec_sid = SMMU_SEC_SID_NS;
>> + } else {
>> + tlbe->sec_sid = PTE_NS(pte) ? SMMU_SEC_SID_NS :
>> SMMU_SEC_SID_S;
>> + }
>> + tlbe->entry.target_as = (tlbe->sec_sid == SMMU_SEC_SID_S)
>> + ? &bs->secure_memory_as :
>> &bs->memory_as;
>
> Having SMMUState passed there would allow to reuse
> smmu_get_address_space.
SMMUState was available here (smmu_ptw_64_s1) . So I'll use
`tlbe->entry.target_as = smmu_get_address_space(bs, tlbe->sec_sid);` in V5.
>
>> tlbe->entry.translated_addr = gpa;
>> tlbe->entry.iova = iova & ~mask;
>> tlbe->entry.addr_mask = mask;
>> @@ -697,7 +736,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
>> dma_addr_t pte_addr = baseaddr + offset * sizeof(pte);
>> uint8_t s2ap;
>> - if (get_pte(baseaddr, offset, &pte, info)) {
>> + if (get_pte(baseaddr, offset, &pte, info, cfg->ns_as,
>> + MEMTXATTRS_UNSPECIFIED)) {
>> goto error;
>> }
>> trace_smmu_ptw_level(stage, level, ipa, subpage_size,
>> @@ -750,6 +790,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
>> goto error_ipa;
>> }
>> + tlbe->sec_sid = SMMU_SEC_SID_NS;
>> + tlbe->entry.target_as = cfg->ns_as;
>> tlbe->entry.translated_addr = gpa;
>> tlbe->entry.iova = ipa & ~mask;
>> tlbe->entry.addr_mask = mask;
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index b8f2fae9a1d..504161ce06d 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -1147,6 +1147,7 @@ epilogue:
>> switch (status) {
>> case SMMU_TRANS_SUCCESS:
>> entry.perm = cached_entry->entry.perm;
>> + entry.target_as = cached_entry->entry.target_as;
>> entry.translated_addr = CACHED_ENTRY_TO_ADDR(cached_entry,
>> addr);
>> entry.addr_mask = cached_entry->entry.addr_mask;
>> trace_smmuv3_translate_success(mr->parent_obj.name, sid, addr,
>
> Overall looks good, and my remarks above are more suggestions than
> blocking comments.
Thanks for your review.
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 14/31] hw/arm/smmu-common: Implement secure state handling in ptw
2026-02-21 10:16 ` [RFC v4 14/31] hw/arm/smmu-common: Implement secure state handling in ptw Tao Tang
2026-02-25 21:12 ` Pierrick Bouvier
@ 2026-03-03 9:41 ` Eric Auger
2026-03-06 10:39 ` Tao Tang
1 sibling, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-03 9:41 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi Tao,
On 2/21/26 11:16 AM, Tao Tang wrote:
> Enhance the page table walker to correctly handle secure and non-secure
> memory accesses. This change introduces logic to select the appropriate
> address space and enforce architectural security policies during walks.
>
> The page table walker now correctly processes Secure Stage 1
> translations. Key changes include:
>
> - The get_pte function now uses the security context to fetch table
> entries from either the Secure or Non-secure address space.
>
> - The stage 1 walker tracks the security state, respecting the NSCFG
> and NSTable attributes. It correctly handles the hierarchical security
> model: if a table descriptor in a secure walk has NSTable=1, all
> subsequent lookups for that walk are forced into the Non-secure space.
> This is a one-way transition, as specified by the architecture.
>
> - The final TLB entry is tagged with the correct output address space,
> ensuring proper memory isolation.
>
> Note: We do not yet support secure stage 2 translations. So ns_as member
> in SMMUTransCfg is used to cache non-secure AS instead of refactoring
> smmu_ptw_64_s2 to pass SMMUState context.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 50 ++++++++++++++++++++++++++++++++++++++++----
> hw/arm/smmuv3.c | 1 +
> 2 files changed, 47 insertions(+), 4 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index a732303b28b..84e71df6767 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -406,15 +406,16 @@ void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
> /**
> * get_pte - Get the content of a page table entry located at
> * @base_addr[@index]
> + * @as: AddressSpace to read from
while at it let's properly document all parameters in the doc comment.
> */
> static int get_pte(dma_addr_t baseaddr, uint32_t index, uint64_t *pte,
> - SMMUPTWEventInfo *info)
> + SMMUPTWEventInfo *info, AddressSpace *as, MemTxAttrs attrs)
> {
> int ret;
> dma_addr_t addr = baseaddr + index * sizeof(*pte);
>
> /* TODO: guarantee 64-bit single-copy atomicity */
> - ret = ldq_le_dma(&address_space_memory, addr, pte, MEMTXATTRS_UNSPECIFIED);
> + ret = ldq_le_dma(as, addr, pte, attrs);
>
> if (ret != MEMTX_OK) {
> info->type = SMMU_PTW_ERR_WALK_EABT;
> @@ -538,6 +539,9 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
> SMMUStage stage = cfg->stage;
> SMMUTransTableInfo *tt = select_tt(cfg, iova);
> uint8_t level, granule_sz, inputsize, stride;
> + int nscfg, current_ns, new_nstable;
> + bool sid_is_ns = cfg->sec_sid == SMMU_SEC_SID_NS;
> + bool forced_ns = false; /* Once true, NSTable is ignored */
>
> if (!tt || tt->disabled) {
> info->type = SMMU_PTW_ERR_TRANSLATION;
> @@ -552,6 +556,8 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
>
> baseaddr = extract64(tt->ttb, 0, cfg->oas);
> baseaddr &= ~indexmask;
> + nscfg = tt->nscfg;
> + forced_ns = sid_is_ns || nscfg;
do you really need this forced_ns
can't you simply set current_ns = sid_is_ns || nscfg
with first value of nscfg set to tt->nscfg and next level ones set to
aptable is !current_ns
>
> while (level < VMSA_LEVELS) {
> uint64_t subpage_size = 1ULL << level_shift(level, granule_sz);
> @@ -560,8 +566,17 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
> uint64_t pte, gpa;
> dma_addr_t pte_addr = baseaddr + offset * sizeof(pte);
> uint8_t ap;
> + AddressSpace *pte_as;
> + MemTxAttrs pte_attrs;
>
> - if (get_pte(baseaddr, offset, &pte, info)) {
> + /*
> + * Start in NS for Non-secure streams or CD.NSCFGx == 1.
> + * Once walk is in NS, NSTable is ignored on subsequent levels.
> + */
> + current_ns = forced_ns || nscfg;
> + pte_as = current_ns ? &bs->memory_as : &bs->secure_memory_as;
> + pte_attrs = current_ns ? MEMTXATTRS_UNSPECIFIED : cfg->txattrs;
> + if (get_pte(baseaddr, offset, &pte, info, pte_as, pte_attrs)) {
> goto error;
> }
> trace_smmu_ptw_level(stage, level, iova, subpage_size,
> @@ -586,6 +601,23 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
> goto error;
> }
> }
> +
> + /*
> + * NSTable can switch the walk to NS only while the current walk
> + * level is Secure. Once switched to NS, NSTable is ignored according
> + * to hierarchical control of Secure/Non-secure accesses:
> + * (IHI 0070G.b)13.4.1 Stage 1 page permissions and
> + * (DDI 0487H.a)D8.4.2 Control of Secure or Non-secure memory access
> + */
> + if (!forced_ns) {
> + new_nstable = PTE_NSTABLE(pte);
> + if (new_nstable) {
> + forced_ns = true;
> + nscfg = 1;
> + } else {
> + nscfg = 0;
> + }
> + }
> level++;
> continue;
> } else if (is_page_pte(pte, level)) {
> @@ -628,6 +660,13 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
> goto error;
> }
>
> + if (current_ns) {
> + tlbe->sec_sid = SMMU_SEC_SID_NS;
> + } else {
> + tlbe->sec_sid = PTE_NS(pte) ? SMMU_SEC_SID_NS : SMMU_SEC_SID_S;
> + }
> + tlbe->entry.target_as = (tlbe->sec_sid == SMMU_SEC_SID_S)
> + ? &bs->secure_memory_as : &bs->memory_as;
So I understand you need to set the target_as depending on sec_sid but
not sure why need to store the sec_sid in the tlbe?
> tlbe->entry.translated_addr = gpa;
> tlbe->entry.iova = iova & ~mask;
> tlbe->entry.addr_mask = mask;
> @@ -697,7 +736,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> dma_addr_t pte_addr = baseaddr + offset * sizeof(pte);
> uint8_t s2ap;
>
> - if (get_pte(baseaddr, offset, &pte, info)) {
> + if (get_pte(baseaddr, offset, &pte, info, cfg->ns_as,
> + MEMTXATTRS_UNSPECIFIED)) {
> goto error;
> }
> trace_smmu_ptw_level(stage, level, ipa, subpage_size,
> @@ -750,6 +790,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> goto error_ipa;
> }
>
> + tlbe->sec_sid = SMMU_SEC_SID_NS;
> + tlbe->entry.target_as = cfg->ns_as;
Shouldn't you handle STE.NSCFG in case STE belongs to the secure stream
table (ns_sid=secure) and stage 1 is disabled?
Also shall we handle SMMU_IDR1.ATTR_PERMS_OVR?
> tlbe->entry.translated_addr = gpa;
> tlbe->entry.iova = ipa & ~mask;
> tlbe->entry.addr_mask = mask;
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index b8f2fae9a1d..504161ce06d 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1147,6 +1147,7 @@ epilogue:
> switch (status) {
> case SMMU_TRANS_SUCCESS:
> entry.perm = cached_entry->entry.perm;
> + entry.target_as = cached_entry->entry.target_as;
> entry.translated_addr = CACHED_ENTRY_TO_ADDR(cached_entry, addr);
> entry.addr_mask = cached_entry->entry.addr_mask;
> trace_smmuv3_translate_success(mr->parent_obj.name, sid, addr,
Thanks
Eric
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 14/31] hw/arm/smmu-common: Implement secure state handling in ptw
2026-03-03 9:41 ` Eric Auger
@ 2026-03-06 10:39 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-06 10:39 UTC (permalink / raw)
To: eric.auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi Eric,
On 2026/3/3 17:41, Eric Auger wrote:
> Hi Tao,
>
> On 2/21/26 11:16 AM, Tao Tang wrote:
>> Enhance the page table walker to correctly handle secure and non-secure
>> memory accesses. This change introduces logic to select the appropriate
>> address space and enforce architectural security policies during walks.
>>
>> The page table walker now correctly processes Secure Stage 1
>> translations. Key changes include:
>>
>> - The get_pte function now uses the security context to fetch table
>> entries from either the Secure or Non-secure address space.
>>
>> - The stage 1 walker tracks the security state, respecting the NSCFG
>> and NSTable attributes. It correctly handles the hierarchical security
>> model: if a table descriptor in a secure walk has NSTable=1, all
>> subsequent lookups for that walk are forced into the Non-secure space.
>> This is a one-way transition, as specified by the architecture.
>>
>> - The final TLB entry is tagged with the correct output address space,
>> ensuring proper memory isolation.
>>
>> Note: We do not yet support secure stage 2 translations. So ns_as member
>> in SMMUTransCfg is used to cache non-secure AS instead of refactoring
>> smmu_ptw_64_s2 to pass SMMUState context.
>>
>> Signed-off-by: Tao Tang<tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmu-common.c | 50 ++++++++++++++++++++++++++++++++++++++++----
>> hw/arm/smmuv3.c | 1 +
>> 2 files changed, 47 insertions(+), 4 deletions(-)
>>
>> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
>> index a732303b28b..84e71df6767 100644
>> --- a/hw/arm/smmu-common.c
>> +++ b/hw/arm/smmu-common.c
>> @@ -406,15 +406,16 @@ void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
>> /**
>> * get_pte - Get the content of a page table entry located at
>> * @base_addr[@index]
>> + * @as: AddressSpace to read from
> while at it let's properly document all parameters in the doc comment.
I'll doc attrs in V5.
>> */
>> static int get_pte(dma_addr_t baseaddr, uint32_t index, uint64_t *pte,
>> - SMMUPTWEventInfo *info)
>> + SMMUPTWEventInfo *info, AddressSpace *as, MemTxAttrs attrs)
>> {
>> int ret;
>> dma_addr_t addr = baseaddr + index * sizeof(*pte);
>>
>> /* TODO: guarantee 64-bit single-copy atomicity */
>> - ret = ldq_le_dma(&address_space_memory, addr, pte, MEMTXATTRS_UNSPECIFIED);
>> + ret = ldq_le_dma(as, addr, pte, attrs);
>>
>> if (ret != MEMTX_OK) {
>> info->type = SMMU_PTW_ERR_WALK_EABT;
>> @@ -538,6 +539,9 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
>> SMMUStage stage = cfg->stage;
>> SMMUTransTableInfo *tt = select_tt(cfg, iova);
>> uint8_t level, granule_sz, inputsize, stride;
>> + int nscfg, current_ns, new_nstable;
>> + bool sid_is_ns = cfg->sec_sid == SMMU_SEC_SID_NS;
>> + bool forced_ns = false; /* Once true, NSTable is ignored */
>>
>> if (!tt || tt->disabled) {
>> info->type = SMMU_PTW_ERR_TRANSLATION;
>> @@ -552,6 +556,8 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
>>
>> baseaddr = extract64(tt->ttb, 0, cfg->oas);
>> baseaddr &= ~indexmask;
>> + nscfg = tt->nscfg;
>> + forced_ns = sid_is_ns || nscfg;
> do you really need this forced_ns
> can't you simply set current_ns = sid_is_ns || nscfg
> with first value of nscfg set to tt->nscfg and next level ones set to
> aptable is !current_ns
You're right. forced_ns could be simplified.
>>
>> while (level < VMSA_LEVELS) {
>> uint64_t subpage_size = 1ULL << level_shift(level, granule_sz); @@ -560,8 +566,17 @@ static int
>> smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg, uint64_t pte, gpa;
>> dma_addr_t pte_addr = baseaddr + offset * sizeof(pte); uint8_t ap; +
>> AddressSpace *pte_as; + MemTxAttrs pte_attrs; - if (get_pte(baseaddr,
>> offset, &pte, info)) { + /* + * Start in NS for Non-secure streams or
>> CD.NSCFGx == 1. + * Once walk is in NS, NSTable is ignored on
>> subsequent levels. + */ + current_ns = forced_ns || nscfg; + pte_as =
>> current_ns ? &bs->memory_as : &bs->secure_memory_as;
>> + pte_attrs = current_ns ? MEMTXATTRS_UNSPECIFIED : cfg->txattrs;
>> + if (get_pte(baseaddr, offset, &pte, info, pte_as, pte_attrs)) {
>> goto error;
>> }
>> trace_smmu_ptw_level(stage, level, iova, subpage_size,
>> @@ -586,6 +601,23 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
>> goto error;
>> }
>> }
>> +
>> + /*
>> + * NSTable can switch the walk to NS only while the current walk
>> + * level is Secure. Once switched to NS, NSTable is ignored according
>> + * to hierarchical control of Secure/Non-secure accesses:
>> + * (IHI 0070G.b)13.4.1 Stage 1 page permissions and
>> + * (DDI 0487H.a)D8.4.2 Control of Secure or Non-secure memory access
>> + */
>> + if (!forced_ns) {
>> + new_nstable = PTE_NSTABLE(pte);
>> + if (new_nstable) {
>> + forced_ns = true;
>> + nscfg = 1;
>> + } else {
>> + nscfg = 0;
>> + }
>> + }
>> level++;
>> continue;
>> } else if (is_page_pte(pte, level)) {
>> @@ -628,6 +660,13 @@ static int smmu_ptw_64_s1(SMMUState *bs, SMMUTransCfg *cfg,
>> goto error;
>> }
>>
>> + if (current_ns) {
>> + tlbe->sec_sid = SMMU_SEC_SID_NS;
>> + } else {
>> + tlbe->sec_sid = PTE_NS(pte) ? SMMU_SEC_SID_NS : SMMU_SEC_SID_S;
>> + }
>> + tlbe->entry.target_as = (tlbe->sec_sid == SMMU_SEC_SID_S)
>> + ? &bs->secure_memory_as : &bs->memory_as;
> So I understand you need to set the target_as depending on sec_sid but
> not sure why need to store the sec_sid in the tlbe?
I will directly use a local sec_sid instead to generate target_as and
drop sec_sid in tlbe as the previous thread mentioned.
>> tlbe->entry.translated_addr = gpa;
>> tlbe->entry.iova = iova & ~mask;
>> tlbe->entry.addr_mask = mask;
>> @@ -697,7 +736,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
>> dma_addr_t pte_addr = baseaddr + offset * sizeof(pte);
>> uint8_t s2ap;
>>
>> - if (get_pte(baseaddr, offset, &pte, info)) {
>> + if (get_pte(baseaddr, offset, &pte, info, cfg->ns_as,
>> + MEMTXATTRS_UNSPECIFIED)) {
>> goto error;
>> }
>> trace_smmu_ptw_level(stage, level, ipa, subpage_size,
>> @@ -750,6 +790,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
>> goto error_ipa;
>> }
>>
>> + tlbe->sec_sid = SMMU_SEC_SID_NS;
>> + tlbe->entry.target_as = cfg->ns_as;
> Shouldn't you handle STE.NSCFG in case STE belongs to the secure stream
> table (ns_sid=secure) and stage 1 is disabled?
>
> Also shall we handle SMMU_IDR1.ATTR_PERMS_OVR?
I indeed ignored all Secure-related handling in stage-2, as I originally
planned to implement those parts in the upcoming S_IDR1.SEL2 feature series.
But the senario you mentioned seems to unrelated to SEL2 feature afer I
rechecked the manual. So I'll implement it in V5 with handling
SMMU_IDR1.ATTR_PERMS_OVR.
Best regards,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 15/31] hw/arm/smmuv3: Tag IOTLB cache keys with SEC_SID
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (13 preceding siblings ...)
2026-02-21 10:16 ` [RFC v4 14/31] hw/arm/smmu-common: Implement secure state handling in ptw Tao Tang
@ 2026-02-21 10:16 ` Tao Tang
2026-02-25 21:21 ` Pierrick Bouvier
2026-03-03 7:40 ` Eric Auger
2026-02-21 10:17 ` [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path Tao Tang
` (15 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:16 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
To prevent aliasing between secure and non-secure translations for the
same address space, the IOTLB lookup key must incorporate the security
state of the transaction.
This commit:
- expands SMMUIOTLBKey with SEC_SID field for cache key differentiation
- extends SMMUIOTLBPageInvInfo with SEC_SID for invalidation filtering
- updates all IOTLB invalidation helpers (smmu_iotlb_inv_iova,
smmu_iotlb_inv_ipa, smmu_iotlb_inv_asid_vmid, smmu_iotlb_inv_vmid,
smmu_iotlb_inv_vmid_s1) to accept and filter by SEC_SID
- plumbs SEC_SID through smmuv3_range_inval for TLB invalidation
- enhances trace events to include SEC_SID for better debugging
This ensures that secure and non-secure TLB entries are treated as
distinct entities within the cache, preventing TLB pollution between
different worlds.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmu-common.c | 80 ++++++++++++++++++++++++------------
hw/arm/smmu-internal.h | 2 +
hw/arm/smmuv3.c | 36 ++++++++--------
hw/arm/trace-events | 12 +++---
include/hw/arm/smmu-common.h | 16 +++++---
5 files changed, 92 insertions(+), 54 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 84e71df6767..bb43430cc3b 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -95,7 +95,7 @@ static guint smmu_iotlb_key_hash(gconstpointer v)
/* Jenkins hash */
a = b = c = JHASH_INITVAL + sizeof(*key);
- a += key->asid + key->vmid + key->level + key->tg;
+ a += key->asid + key->vmid + key->level + key->tg + key->sec_sid;
b += extract64(key->iova, 0, 32);
c += extract64(key->iova, 32, 32);
@@ -111,14 +111,15 @@ static gboolean smmu_iotlb_key_equal(gconstpointer v1, gconstpointer v2)
return (k1->asid == k2->asid) && (k1->iova == k2->iova) &&
(k1->level == k2->level) && (k1->tg == k2->tg) &&
- (k1->vmid == k2->vmid);
+ (k1->vmid == k2->vmid) && (k1->sec_sid == k2->sec_sid);
}
SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
- uint8_t tg, uint8_t level)
+ uint8_t tg, uint8_t level,
+ SMMUSecSID sec_sid)
{
SMMUIOTLBKey key = {.asid = asid, .vmid = vmid, .iova = iova,
- .tg = tg, .level = level};
+ .tg = tg, .level = level, .sec_sid = sec_sid};
return key;
}
@@ -140,7 +141,7 @@ static SMMUTLBEntry *smmu_iotlb_lookup_all_levels(SMMUState *bs,
SMMUIOTLBKey key;
key = smmu_get_iotlb_key(cfg->asid, cfg->s2cfg.vmid,
- iova & ~mask, tg, level);
+ iova & ~mask, tg, level, cfg->sec_sid);
entry = g_hash_table_lookup(bs->iotlb, &key);
if (entry) {
break;
@@ -204,7 +205,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new)
}
*key = smmu_get_iotlb_key(cfg->asid, cfg->s2cfg.vmid, new->entry.iova,
- tg, new->level);
+ tg, new->level, cfg->sec_sid);
trace_smmu_iotlb_insert(cfg->asid, cfg->s2cfg.vmid, new->entry.iova,
tg, new->level);
g_hash_table_insert(bs->iotlb, key, new);
@@ -223,26 +224,29 @@ static gboolean smmu_hash_remove_by_asid_vmid(gpointer key, gpointer value,
SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
return (SMMU_IOTLB_ASID(*iotlb_key) == info->asid) &&
- (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid);
+ (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid) &&
+ (SMMU_IOTLB_SEC_SID(*iotlb_key) == info->sec_sid);
}
static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
gpointer user_data)
{
- int vmid = *(int *)user_data;
+ SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
- return SMMU_IOTLB_VMID(*iotlb_key) == vmid;
+ return (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid) &&
+ (SMMU_IOTLB_SEC_SID(*iotlb_key) == info->sec_sid);
}
static gboolean smmu_hash_remove_by_vmid_s1(gpointer key, gpointer value,
gpointer user_data)
{
- int vmid = *(int *)user_data;
+ SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
- return (SMMU_IOTLB_VMID(*iotlb_key) == vmid) &&
- (SMMU_IOTLB_ASID(*iotlb_key) >= 0);
+ return (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid) &&
+ (SMMU_IOTLB_ASID(*iotlb_key) >= 0) &&
+ (SMMU_IOTLB_SEC_SID(*iotlb_key) == info->sec_sid);
}
static gboolean smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer value,
@@ -259,6 +263,9 @@ static gboolean smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer value,
if (info->vmid >= 0 && info->vmid != SMMU_IOTLB_VMID(iotlb_key)) {
return false;
}
+ if (info->sec_sid != SMMU_IOTLB_SEC_SID(iotlb_key)) {
+ return false;
+ }
return ((info->iova & ~entry->addr_mask) == entry->iova) ||
((entry->iova & ~info->mask) == info->iova);
}
@@ -278,6 +285,9 @@ static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
if (info->vmid != SMMU_IOTLB_VMID(iotlb_key)) {
return false;
}
+ if (info->sec_sid != SMMU_IOTLB_SEC_SID(iotlb_key)) {
+ return false;
+ }
return ((info->iova & ~entry->addr_mask) == entry->iova) ||
((entry->iova & ~info->mask) == info->iova);
}
@@ -323,13 +333,15 @@ void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev)
}
void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
- uint8_t tg, uint64_t num_pages, uint8_t ttl)
+ uint8_t tg, uint64_t num_pages, uint8_t ttl,
+ SMMUSecSID sec_sid)
{
/* if tg is not set we use 4KB range invalidation */
uint8_t granule = tg ? tg * 2 + 10 : 12;
if (ttl && (num_pages == 1) && (asid >= 0)) {
- SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, iova, tg, ttl);
+ SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, iova,
+ tg, ttl, sec_sid);
if (g_hash_table_remove(s->iotlb, &key)) {
return;
@@ -343,7 +355,8 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
SMMUIOTLBPageInvInfo info = {
.asid = asid, .iova = iova,
.vmid = vmid,
- .mask = (num_pages * 1 << granule) - 1};
+ .mask = (num_pages * 1 << granule) - 1,
+ .sec_sid = sec_sid};
g_hash_table_foreach_remove(s->iotlb,
smmu_hash_remove_by_asid_vmid_iova,
@@ -355,13 +368,15 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
* in Stage-1 invalidation ASID = -1, means don't care.
*/
void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
- uint64_t num_pages, uint8_t ttl)
+ uint64_t num_pages, uint8_t ttl,
+ SMMUSecSID sec_sid)
{
uint8_t granule = tg ? tg * 2 + 10 : 12;
int asid = -1;
if (ttl && (num_pages == 1)) {
- SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, ipa, tg, ttl);
+ SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, ipa,
+ tg, ttl, sec_sid);
if (g_hash_table_remove(s->iotlb, &key)) {
return;
@@ -371,34 +386,47 @@ void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
SMMUIOTLBPageInvInfo info = {
.iova = ipa,
.vmid = vmid,
- .mask = (num_pages << granule) - 1};
+ .mask = (num_pages << granule) - 1,
+ .sec_sid = sec_sid};
g_hash_table_foreach_remove(s->iotlb,
smmu_hash_remove_by_vmid_ipa,
&info);
}
-void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid)
+void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid,
+ SMMUSecSID sec_sid)
{
SMMUIOTLBPageInvInfo info = {
.asid = asid,
.vmid = vmid,
+ .sec_sid = sec_sid,
};
- trace_smmu_iotlb_inv_asid_vmid(asid, vmid);
+ trace_smmu_iotlb_inv_asid_vmid(sec_sid, asid, vmid);
g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid_vmid, &info);
}
-void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
+void smmu_iotlb_inv_vmid(SMMUState *s, int vmid, SMMUSecSID sec_sid)
{
- trace_smmu_iotlb_inv_vmid(vmid);
- g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
+ SMMUIOTLBPageInvInfo info = {
+ .vmid = vmid,
+ .sec_sid = sec_sid,
+ };
+
+ trace_smmu_iotlb_inv_vmid(sec_sid, vmid);
+ g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &info);
}
-void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
+void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid, SMMUSecSID sec_sid)
{
- trace_smmu_iotlb_inv_vmid_s1(vmid);
- g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid_s1, &vmid);
+ SMMUIOTLBPageInvInfo info = {
+ .vmid = vmid,
+ .sec_sid = sec_sid,
+ };
+
+ trace_smmu_iotlb_inv_vmid_s1(sec_sid, vmid);
+ g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid_s1, &info);
}
/* VMSAv8-64 Translation */
diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h
index a0454f720da..5ddd0372d5b 100644
--- a/hw/arm/smmu-internal.h
+++ b/hw/arm/smmu-internal.h
@@ -145,12 +145,14 @@ static inline int pgd_concat_idx(int start_level, int granule_sz,
#define SMMU_IOTLB_ASID(key) ((key).asid)
#define SMMU_IOTLB_VMID(key) ((key).vmid)
+#define SMMU_IOTLB_SEC_SID(key) ((key).sec_sid)
typedef struct SMMUIOTLBPageInvInfo {
int asid;
int vmid;
uint64_t iova;
uint64_t mask;
+ SMMUSecSID sec_sid;
} SMMUIOTLBPageInvInfo;
#endif
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 504161ce06d..4a4de719a7c 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1279,7 +1279,8 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
}
}
-static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
+static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
+ SMMUSecSID sec_sid)
{
dma_addr_t end, addr = CMD_ADDR(cmd);
uint8_t type = CMD_TYPE(cmd);
@@ -1304,12 +1305,13 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
}
if (!tg) {
- trace_smmuv3_range_inval(vmid, asid, addr, tg, 1, ttl, leaf, stage);
+ trace_smmuv3_range_inval(sec_sid, vmid, asid, addr,
+ tg, 1, ttl, leaf, stage);
smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage);
if (stage == SMMU_STAGE_1) {
- smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl);
+ smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl, sec_sid);
} else {
- smmu_iotlb_inv_ipa(s, vmid, addr, tg, 1, ttl);
+ smmu_iotlb_inv_ipa(s, vmid, addr, tg, 1, ttl, sec_sid);
}
return;
}
@@ -1326,13 +1328,15 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
uint64_t mask = dma_aligned_pow2_mask(addr, end, 64);
num_pages = (mask + 1) >> granule;
- trace_smmuv3_range_inval(vmid, asid, addr, tg, num_pages,
- ttl, leaf, stage);
- smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, num_pages, stage);
+ trace_smmuv3_range_inval(sec_sid, vmid, asid, addr, tg,
+ num_pages, ttl, leaf, stage);
+ smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg,
+ num_pages, stage);
if (stage == SMMU_STAGE_1) {
- smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, num_pages, ttl);
+ smmu_iotlb_inv_iova(s, asid, vmid, addr, tg,
+ num_pages, ttl, sec_sid);
} else {
- smmu_iotlb_inv_ipa(s, vmid, addr, tg, num_pages, ttl);
+ smmu_iotlb_inv_ipa(s, vmid, addr, tg, num_pages, ttl, sec_sid);
}
addr += mask + 1;
}
@@ -1474,9 +1478,9 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
vmid = CMD_VMID(&cmd);
}
- trace_smmuv3_cmdq_tlbi_nh_asid(asid);
+ trace_smmuv3_cmdq_tlbi_nh_asid(sec_sid, asid);
smmu_inv_notifiers_all(&s->smmu_state);
- smmu_iotlb_inv_asid_vmid(bs, asid, vmid);
+ smmu_iotlb_inv_asid_vmid(bs, asid, vmid, sec_sid);
if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
cmd_error = SMMU_CERROR_ILL;
break;
@@ -1498,8 +1502,8 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
*/
if (STAGE2_SUPPORTED(s)) {
vmid = CMD_VMID(&cmd);
- trace_smmuv3_cmdq_tlbi_nh(vmid);
- smmu_iotlb_inv_vmid_s1(bs, vmid);
+ trace_smmuv3_cmdq_tlbi_nh(sec_sid, vmid);
+ smmu_iotlb_inv_vmid_s1(bs, vmid, sec_sid);
break;
}
QEMU_FALLTHROUGH;
@@ -1519,7 +1523,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
cmd_error = SMMU_CERROR_ILL;
break;
}
- smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1);
+ smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1, SMMU_SEC_SID_NS);
if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
cmd_error = SMMU_CERROR_ILL;
break;
@@ -1536,7 +1540,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
trace_smmuv3_cmdq_tlbi_s12_vmid(vmid);
smmu_inv_notifiers_all(&s->smmu_state);
- smmu_iotlb_inv_vmid(bs, vmid);
+ smmu_iotlb_inv_vmid(bs, vmid, SMMU_SEC_SID_NS);
break;
}
case SMMU_CMD_TLBI_S2_IPA:
@@ -1548,7 +1552,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
* As currently only either s1 or s2 are supported
* we can reuse same function for s2.
*/
- smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2);
+ smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2, SMMU_SEC_SID_NS);
break;
case SMMU_CMD_ATC_INV:
{
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index 9c2cc131ab4..4e360b3c0d3 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -18,9 +18,9 @@ smmu_ptw_page_pte(int stage, int level, uint64_t iova, uint64_t baseaddr, uint6
smmu_ptw_block_pte(int stage, int level, uint64_t baseaddr, uint64_t pteaddr, uint64_t pte, uint64_t iova, uint64_t gpa, int bsize_mb) "stage=%d level=%d base@=0x%"PRIx64" pte@=0x%"PRIx64" pte=0x%"PRIx64" iova=0x%"PRIx64" block address = 0x%"PRIx64" block size = %d MiB"
smmu_get_pte(uint64_t baseaddr, int index, uint64_t pteaddr, uint64_t pte) "baseaddr=0x%"PRIx64" index=0x%x, pteaddr=0x%"PRIx64", pte=0x%"PRIx64
smmu_iotlb_inv_all(void) "IOTLB invalidate all"
-smmu_iotlb_inv_asid_vmid(int asid, int vmid) "IOTLB invalidate asid=%d vmid=%d"
-smmu_iotlb_inv_vmid(int vmid) "IOTLB invalidate vmid=%d"
-smmu_iotlb_inv_vmid_s1(int vmid) "IOTLB invalidate vmid=%d"
+smmu_iotlb_inv_asid_vmid(int sec_sid, int asid, int vmid) "IOTLB invalidate sec_sid=%d asid=%d vmid=%d"
+smmu_iotlb_inv_vmid(int sec_sid, int vmid) "IOTLB invalidate sec_sid=%d vmid=%d"
+smmu_iotlb_inv_vmid_s1(int sec_sid, int vmid) "IOTLB invalidate S1 sec_sid=%d vmid=%d"
smmu_iotlb_inv_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
smmu_configs_inv_sid_range(uint32_t start, uint32_t end) "Config cache INV SID range from 0x%x to 0x%x"
smmu_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
@@ -56,10 +56,10 @@ smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%x - end=0x%x"
smmuv3_cmdq_cfgi_cd(uint32_t sid) "sid=0x%x"
smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
-smmuv3_range_inval(int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf, int stage) "vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d stage=%d"
-smmuv3_cmdq_tlbi_nh(int vmid) "vmid=%d"
+smmuv3_range_inval(int sec_sid, int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf, int stage) "sec_sid=%d vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d stage=%d"
+smmuv3_cmdq_tlbi_nh(int sec_sid, int vmid) "sec_sid=%d vmid=%d"
smmuv3_cmdq_tlbi_nsnh(void) ""
-smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
+smmuv3_cmdq_tlbi_nh_asid(int sec_sid, int asid) "sec_sid=%d asid=%d"
smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s"
smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s"
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index b0a02e12fe6..7d1d0936921 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -162,6 +162,7 @@ typedef struct SMMUIOTLBKey {
int vmid;
uint8_t tg;
uint8_t level;
+ SMMUSecSID sec_sid;
} SMMUIOTLBKey;
typedef struct SMMUConfigKey {
@@ -256,16 +257,19 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
SMMUTransTableInfo *tt, hwaddr iova);
void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *entry);
SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
- uint8_t tg, uint8_t level);
+ uint8_t tg, uint8_t level, SMMUSecSID sec_sid);
SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID sec_sid);
void smmu_iotlb_inv_all(SMMUState *s);
-void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid);
-void smmu_iotlb_inv_vmid(SMMUState *s, int vmid);
-void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid);
+void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid,
+ SMMUSecSID sec_sid);
+void smmu_iotlb_inv_vmid(SMMUState *s, int vmid, SMMUSecSID sec_sid);
+void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid, SMMUSecSID sec_sid);
void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
- uint8_t tg, uint64_t num_pages, uint8_t ttl);
+ uint8_t tg, uint64_t num_pages, uint8_t ttl,
+ SMMUSecSID sec_sid);
void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
- uint64_t num_pages, uint8_t ttl);
+ uint64_t num_pages, uint8_t ttl,
+ SMMUSecSID sec_sid);
void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range);
void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev);
/* Unmap the range of all the notifiers registered to any IOMMU mr */
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 15/31] hw/arm/smmuv3: Tag IOTLB cache keys with SEC_SID
2026-02-21 10:16 ` [RFC v4 15/31] hw/arm/smmuv3: Tag IOTLB cache keys with SEC_SID Tao Tang
@ 2026-02-25 21:21 ` Pierrick Bouvier
2026-03-03 7:40 ` Eric Auger
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:21 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:16 AM, Tao Tang wrote:
> To prevent aliasing between secure and non-secure translations for the
> same address space, the IOTLB lookup key must incorporate the security
> state of the transaction.
>
> This commit:
> - expands SMMUIOTLBKey with SEC_SID field for cache key differentiation
> - extends SMMUIOTLBPageInvInfo with SEC_SID for invalidation filtering
> - updates all IOTLB invalidation helpers (smmu_iotlb_inv_iova,
> smmu_iotlb_inv_ipa, smmu_iotlb_inv_asid_vmid, smmu_iotlb_inv_vmid,
> smmu_iotlb_inv_vmid_s1) to accept and filter by SEC_SID
> - plumbs SEC_SID through smmuv3_range_inval for TLB invalidation
> - enhances trace events to include SEC_SID for better debugging
>
> This ensures that secure and non-secure TLB entries are treated as
> distinct entities within the cache, preventing TLB pollution between
> different worlds.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 80 ++++++++++++++++++++++++------------
> hw/arm/smmu-internal.h | 2 +
> hw/arm/smmuv3.c | 36 ++++++++--------
> hw/arm/trace-events | 12 +++---
> include/hw/arm/smmu-common.h | 16 +++++---
> 5 files changed, 92 insertions(+), 54 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 15/31] hw/arm/smmuv3: Tag IOTLB cache keys with SEC_SID
2026-02-21 10:16 ` [RFC v4 15/31] hw/arm/smmuv3: Tag IOTLB cache keys with SEC_SID Tao Tang
2026-02-25 21:21 ` Pierrick Bouvier
@ 2026-03-03 7:40 ` Eric Auger
2026-03-05 15:54 ` Tao Tang
1 sibling, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-03 7:40 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 2/21/26 11:16 AM, Tao Tang wrote:
> To prevent aliasing between secure and non-secure translations for the
> same address space, the IOTLB lookup key must incorporate the security
> state of the transaction.
>
> This commit:
> - expands SMMUIOTLBKey with SEC_SID field for cache key differentiation
> - extends SMMUIOTLBPageInvInfo with SEC_SID for invalidation filtering
> - updates all IOTLB invalidation helpers (smmu_iotlb_inv_iova,
> smmu_iotlb_inv_ipa, smmu_iotlb_inv_asid_vmid, smmu_iotlb_inv_vmid,
> smmu_iotlb_inv_vmid_s1) to accept and filter by SEC_SID
> - plumbs SEC_SID through smmuv3_range_inval for TLB invalidation
> - enhances trace events to include SEC_SID for better debugging
>
> This ensures that secure and non-secure TLB entries are treated as
> distinct entities within the cache, preventing TLB pollution between
> different worlds.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 80 ++++++++++++++++++++++++------------
> hw/arm/smmu-internal.h | 2 +
> hw/arm/smmuv3.c | 36 ++++++++--------
> hw/arm/trace-events | 12 +++---
> include/hw/arm/smmu-common.h | 16 +++++---
> 5 files changed, 92 insertions(+), 54 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index 84e71df6767..bb43430cc3b 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -95,7 +95,7 @@ static guint smmu_iotlb_key_hash(gconstpointer v)
>
> /* Jenkins hash */
> a = b = c = JHASH_INITVAL + sizeof(*key);
> - a += key->asid + key->vmid + key->level + key->tg;
> + a += key->asid + key->vmid + key->level + key->tg + key->sec_sid;
> b += extract64(key->iova, 0, 32);
> c += extract64(key->iova, 32, 32);
>
> @@ -111,14 +111,15 @@ static gboolean smmu_iotlb_key_equal(gconstpointer v1, gconstpointer v2)
>
> return (k1->asid == k2->asid) && (k1->iova == k2->iova) &&
> (k1->level == k2->level) && (k1->tg == k2->tg) &&
> - (k1->vmid == k2->vmid);
> + (k1->vmid == k2->vmid) && (k1->sec_sid == k2->sec_sid);
> }
>
> SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> - uint8_t tg, uint8_t level)
> + uint8_t tg, uint8_t level,
> + SMMUSecSID sec_sid)
> {
> SMMUIOTLBKey key = {.asid = asid, .vmid = vmid, .iova = iova,
> - .tg = tg, .level = level};
> + .tg = tg, .level = level, .sec_sid = sec_sid};
>
> return key;
> }
> @@ -140,7 +141,7 @@ static SMMUTLBEntry *smmu_iotlb_lookup_all_levels(SMMUState *bs,
> SMMUIOTLBKey key;
>
> key = smmu_get_iotlb_key(cfg->asid, cfg->s2cfg.vmid,
> - iova & ~mask, tg, level);
> + iova & ~mask, tg, level, cfg->sec_sid);
> entry = g_hash_table_lookup(bs->iotlb, &key);
> if (entry) {
> break;
> @@ -204,7 +205,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new)
> }
>
> *key = smmu_get_iotlb_key(cfg->asid, cfg->s2cfg.vmid, new->entry.iova,
> - tg, new->level);
> + tg, new->level, cfg->sec_sid);
> trace_smmu_iotlb_insert(cfg->asid, cfg->s2cfg.vmid, new->entry.iova,
> tg, new->level);
Please update all tracepoints with the additional sec_sid. See also
trace_smmu_iotlb_lookup_hit/miss
One question, the spec says in "TLB tagging, VMIDs, ASIDs and
participation in boradcats TLB maintenance" that cached trasnlations are
tagged with
"A translation regime, given by the STE’s StreamWorld and derived in
part from STE.STRW"
Can you confirm this matches our sec_sid?
Thanks
Eric
> g_hash_table_insert(bs->iotlb, key, new);
> @@ -223,26 +224,29 @@ static gboolean smmu_hash_remove_by_asid_vmid(gpointer key, gpointer value,
> SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
>
> return (SMMU_IOTLB_ASID(*iotlb_key) == info->asid) &&
> - (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid);
> + (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid) &&
> + (SMMU_IOTLB_SEC_SID(*iotlb_key) == info->sec_sid);
> }
>
> static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
> gpointer user_data)
> {
> - int vmid = *(int *)user_data;
> + SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
> SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
>
> - return SMMU_IOTLB_VMID(*iotlb_key) == vmid;
> + return (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid) &&
> + (SMMU_IOTLB_SEC_SID(*iotlb_key) == info->sec_sid);
> }
>
> static gboolean smmu_hash_remove_by_vmid_s1(gpointer key, gpointer value,
> gpointer user_data)
> {
> - int vmid = *(int *)user_data;
> + SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
> SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
>
> - return (SMMU_IOTLB_VMID(*iotlb_key) == vmid) &&
> - (SMMU_IOTLB_ASID(*iotlb_key) >= 0);
> + return (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid) &&
> + (SMMU_IOTLB_ASID(*iotlb_key) >= 0) &&
> + (SMMU_IOTLB_SEC_SID(*iotlb_key) == info->sec_sid);
> }
>
> static gboolean smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer value,
> @@ -259,6 +263,9 @@ static gboolean smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer value,
> if (info->vmid >= 0 && info->vmid != SMMU_IOTLB_VMID(iotlb_key)) {
> return false;
> }
> + if (info->sec_sid != SMMU_IOTLB_SEC_SID(iotlb_key)) {
> + return false;
> + }
> return ((info->iova & ~entry->addr_mask) == entry->iova) ||
> ((entry->iova & ~info->mask) == info->iova);
> }
> @@ -278,6 +285,9 @@ static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
> if (info->vmid != SMMU_IOTLB_VMID(iotlb_key)) {
> return false;
> }
> + if (info->sec_sid != SMMU_IOTLB_SEC_SID(iotlb_key)) {
> + return false;
> + }
> return ((info->iova & ~entry->addr_mask) == entry->iova) ||
> ((entry->iova & ~info->mask) == info->iova);
> }
> @@ -323,13 +333,15 @@ void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev)
> }
>
> void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> - uint8_t tg, uint64_t num_pages, uint8_t ttl)
> + uint8_t tg, uint64_t num_pages, uint8_t ttl,
> + SMMUSecSID sec_sid)
> {
> /* if tg is not set we use 4KB range invalidation */
> uint8_t granule = tg ? tg * 2 + 10 : 12;
>
> if (ttl && (num_pages == 1) && (asid >= 0)) {
> - SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, iova, tg, ttl);
> + SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, iova,
> + tg, ttl, sec_sid);
>
> if (g_hash_table_remove(s->iotlb, &key)) {
> return;
> @@ -343,7 +355,8 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> SMMUIOTLBPageInvInfo info = {
> .asid = asid, .iova = iova,
> .vmid = vmid,
> - .mask = (num_pages * 1 << granule) - 1};
> + .mask = (num_pages * 1 << granule) - 1,
> + .sec_sid = sec_sid};
>
> g_hash_table_foreach_remove(s->iotlb,
> smmu_hash_remove_by_asid_vmid_iova,
> @@ -355,13 +368,15 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> * in Stage-1 invalidation ASID = -1, means don't care.
> */
> void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
> - uint64_t num_pages, uint8_t ttl)
> + uint64_t num_pages, uint8_t ttl,
> + SMMUSecSID sec_sid)
> {
> uint8_t granule = tg ? tg * 2 + 10 : 12;
> int asid = -1;
>
> if (ttl && (num_pages == 1)) {
> - SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, ipa, tg, ttl);
> + SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, ipa,
> + tg, ttl, sec_sid);
>
> if (g_hash_table_remove(s->iotlb, &key)) {
> return;
> @@ -371,34 +386,47 @@ void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
> SMMUIOTLBPageInvInfo info = {
> .iova = ipa,
> .vmid = vmid,
> - .mask = (num_pages << granule) - 1};
> + .mask = (num_pages << granule) - 1,
> + .sec_sid = sec_sid};
>
> g_hash_table_foreach_remove(s->iotlb,
> smmu_hash_remove_by_vmid_ipa,
> &info);
> }
>
> -void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid)
> +void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid,
> + SMMUSecSID sec_sid)
> {
> SMMUIOTLBPageInvInfo info = {
> .asid = asid,
> .vmid = vmid,
> + .sec_sid = sec_sid,
> };
>
> - trace_smmu_iotlb_inv_asid_vmid(asid, vmid);
> + trace_smmu_iotlb_inv_asid_vmid(sec_sid, asid, vmid);
> g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid_vmid, &info);
> }
>
> -void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
> +void smmu_iotlb_inv_vmid(SMMUState *s, int vmid, SMMUSecSID sec_sid)
> {
> - trace_smmu_iotlb_inv_vmid(vmid);
> - g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
> + SMMUIOTLBPageInvInfo info = {
> + .vmid = vmid,
> + .sec_sid = sec_sid,
> + };
> +
> + trace_smmu_iotlb_inv_vmid(sec_sid, vmid);
> + g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &info);
> }
>
> -void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
> +void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid, SMMUSecSID sec_sid)
> {
> - trace_smmu_iotlb_inv_vmid_s1(vmid);
> - g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid_s1, &vmid);
> + SMMUIOTLBPageInvInfo info = {
> + .vmid = vmid,
> + .sec_sid = sec_sid,
> + };
> +
> + trace_smmu_iotlb_inv_vmid_s1(sec_sid, vmid);
> + g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid_s1, &info);
> }
>
> /* VMSAv8-64 Translation */
> diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h
> index a0454f720da..5ddd0372d5b 100644
> --- a/hw/arm/smmu-internal.h
> +++ b/hw/arm/smmu-internal.h
> @@ -145,12 +145,14 @@ static inline int pgd_concat_idx(int start_level, int granule_sz,
>
> #define SMMU_IOTLB_ASID(key) ((key).asid)
> #define SMMU_IOTLB_VMID(key) ((key).vmid)
> +#define SMMU_IOTLB_SEC_SID(key) ((key).sec_sid)
>
> typedef struct SMMUIOTLBPageInvInfo {
> int asid;
> int vmid;
> uint64_t iova;
> uint64_t mask;
> + SMMUSecSID sec_sid;
> } SMMUIOTLBPageInvInfo;
>
> #endif
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 504161ce06d..4a4de719a7c 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1279,7 +1279,8 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
> }
> }
>
> -static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
> +static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
> + SMMUSecSID sec_sid)
> {
> dma_addr_t end, addr = CMD_ADDR(cmd);
> uint8_t type = CMD_TYPE(cmd);
> @@ -1304,12 +1305,13 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
> }
>
> if (!tg) {
> - trace_smmuv3_range_inval(vmid, asid, addr, tg, 1, ttl, leaf, stage);
> + trace_smmuv3_range_inval(sec_sid, vmid, asid, addr,
> + tg, 1, ttl, leaf, stage);
> smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage);
> if (stage == SMMU_STAGE_1) {
> - smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl);
> + smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl, sec_sid);
> } else {
> - smmu_iotlb_inv_ipa(s, vmid, addr, tg, 1, ttl);
> + smmu_iotlb_inv_ipa(s, vmid, addr, tg, 1, ttl, sec_sid);
> }
> return;
> }
> @@ -1326,13 +1328,15 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
> uint64_t mask = dma_aligned_pow2_mask(addr, end, 64);
>
> num_pages = (mask + 1) >> granule;
> - trace_smmuv3_range_inval(vmid, asid, addr, tg, num_pages,
> - ttl, leaf, stage);
> - smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, num_pages, stage);
> + trace_smmuv3_range_inval(sec_sid, vmid, asid, addr, tg,
> + num_pages, ttl, leaf, stage);
> + smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg,
> + num_pages, stage);
> if (stage == SMMU_STAGE_1) {
> - smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, num_pages, ttl);
> + smmu_iotlb_inv_iova(s, asid, vmid, addr, tg,
> + num_pages, ttl, sec_sid);
> } else {
> - smmu_iotlb_inv_ipa(s, vmid, addr, tg, num_pages, ttl);
> + smmu_iotlb_inv_ipa(s, vmid, addr, tg, num_pages, ttl, sec_sid);
> }
> addr += mask + 1;
> }
> @@ -1474,9 +1478,9 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> vmid = CMD_VMID(&cmd);
> }
>
> - trace_smmuv3_cmdq_tlbi_nh_asid(asid);
> + trace_smmuv3_cmdq_tlbi_nh_asid(sec_sid, asid);
> smmu_inv_notifiers_all(&s->smmu_state);
> - smmu_iotlb_inv_asid_vmid(bs, asid, vmid);
> + smmu_iotlb_inv_asid_vmid(bs, asid, vmid, sec_sid);
> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
> cmd_error = SMMU_CERROR_ILL;
> break;
> @@ -1498,8 +1502,8 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> */
> if (STAGE2_SUPPORTED(s)) {
> vmid = CMD_VMID(&cmd);
> - trace_smmuv3_cmdq_tlbi_nh(vmid);
> - smmu_iotlb_inv_vmid_s1(bs, vmid);
> + trace_smmuv3_cmdq_tlbi_nh(sec_sid, vmid);
> + smmu_iotlb_inv_vmid_s1(bs, vmid, sec_sid);
> break;
> }
> QEMU_FALLTHROUGH;
> @@ -1519,7 +1523,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> cmd_error = SMMU_CERROR_ILL;
> break;
> }
> - smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1);
> + smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1, SMMU_SEC_SID_NS);
> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
> cmd_error = SMMU_CERROR_ILL;
> break;
> @@ -1536,7 +1540,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
>
> trace_smmuv3_cmdq_tlbi_s12_vmid(vmid);
> smmu_inv_notifiers_all(&s->smmu_state);
> - smmu_iotlb_inv_vmid(bs, vmid);
> + smmu_iotlb_inv_vmid(bs, vmid, SMMU_SEC_SID_NS);
> break;
> }
> case SMMU_CMD_TLBI_S2_IPA:
> @@ -1548,7 +1552,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> * As currently only either s1 or s2 are supported
> * we can reuse same function for s2.
> */
> - smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2);
> + smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2, SMMU_SEC_SID_NS);
> break;
> case SMMU_CMD_ATC_INV:
> {
> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> index 9c2cc131ab4..4e360b3c0d3 100644
> --- a/hw/arm/trace-events
> +++ b/hw/arm/trace-events
> @@ -18,9 +18,9 @@ smmu_ptw_page_pte(int stage, int level, uint64_t iova, uint64_t baseaddr, uint6
> smmu_ptw_block_pte(int stage, int level, uint64_t baseaddr, uint64_t pteaddr, uint64_t pte, uint64_t iova, uint64_t gpa, int bsize_mb) "stage=%d level=%d base@=0x%"PRIx64" pte@=0x%"PRIx64" pte=0x%"PRIx64" iova=0x%"PRIx64" block address = 0x%"PRIx64" block size = %d MiB"
> smmu_get_pte(uint64_t baseaddr, int index, uint64_t pteaddr, uint64_t pte) "baseaddr=0x%"PRIx64" index=0x%x, pteaddr=0x%"PRIx64", pte=0x%"PRIx64
> smmu_iotlb_inv_all(void) "IOTLB invalidate all"
> -smmu_iotlb_inv_asid_vmid(int asid, int vmid) "IOTLB invalidate asid=%d vmid=%d"
> -smmu_iotlb_inv_vmid(int vmid) "IOTLB invalidate vmid=%d"
> -smmu_iotlb_inv_vmid_s1(int vmid) "IOTLB invalidate vmid=%d"
> +smmu_iotlb_inv_asid_vmid(int sec_sid, int asid, int vmid) "IOTLB invalidate sec_sid=%d asid=%d vmid=%d"
> +smmu_iotlb_inv_vmid(int sec_sid, int vmid) "IOTLB invalidate sec_sid=%d vmid=%d"
> +smmu_iotlb_inv_vmid_s1(int sec_sid, int vmid) "IOTLB invalidate S1 sec_sid=%d vmid=%d"
> smmu_iotlb_inv_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
> smmu_configs_inv_sid_range(uint32_t start, uint32_t end) "Config cache INV SID range from 0x%x to 0x%x"
> smmu_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
> @@ -56,10 +56,10 @@ smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%x - end=0x%x"
> smmuv3_cmdq_cfgi_cd(uint32_t sid) "sid=0x%x"
> smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
> smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
> -smmuv3_range_inval(int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf, int stage) "vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d stage=%d"
> -smmuv3_cmdq_tlbi_nh(int vmid) "vmid=%d"
> +smmuv3_range_inval(int sec_sid, int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf, int stage) "sec_sid=%d vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d stage=%d"
> +smmuv3_cmdq_tlbi_nh(int sec_sid, int vmid) "sec_sid=%d vmid=%d"
> smmuv3_cmdq_tlbi_nsnh(void) ""
> -smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
> +smmuv3_cmdq_tlbi_nh_asid(int sec_sid, int asid) "sec_sid=%d asid=%d"
> smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
> smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s"
> smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s"
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index b0a02e12fe6..7d1d0936921 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -162,6 +162,7 @@ typedef struct SMMUIOTLBKey {
> int vmid;
> uint8_t tg;
> uint8_t level;
> + SMMUSecSID sec_sid;
> } SMMUIOTLBKey;
>
> typedef struct SMMUConfigKey {
> @@ -256,16 +257,19 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> SMMUTransTableInfo *tt, hwaddr iova);
> void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *entry);
> SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> - uint8_t tg, uint8_t level);
> + uint8_t tg, uint8_t level, SMMUSecSID sec_sid);
> SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID sec_sid);
> void smmu_iotlb_inv_all(SMMUState *s);
> -void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid);
> -void smmu_iotlb_inv_vmid(SMMUState *s, int vmid);
> -void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid);
> +void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid,
> + SMMUSecSID sec_sid);
> +void smmu_iotlb_inv_vmid(SMMUState *s, int vmid, SMMUSecSID sec_sid);
> +void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid, SMMUSecSID sec_sid);
> void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> - uint8_t tg, uint64_t num_pages, uint8_t ttl);
> + uint8_t tg, uint64_t num_pages, uint8_t ttl,
> + SMMUSecSID sec_sid);
> void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
> - uint64_t num_pages, uint8_t ttl);
> + uint64_t num_pages, uint8_t ttl,
> + SMMUSecSID sec_sid);
> void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range);
> void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev);
> /* Unmap the range of all the notifiers registered to any IOMMU mr */
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 15/31] hw/arm/smmuv3: Tag IOTLB cache keys with SEC_SID
2026-03-03 7:40 ` Eric Auger
@ 2026-03-05 15:54 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-05 15:54 UTC (permalink / raw)
To: eric.auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi Eric,
On 2026/3/3 15:40, Eric Auger wrote:
>
> On 2/21/26 11:16 AM, Tao Tang wrote:
>> To prevent aliasing between secure and non-secure translations for the
>> same address space, the IOTLB lookup key must incorporate the security
>> state of the transaction.
>>
>> This commit:
>> - expands SMMUIOTLBKey with SEC_SID field for cache key differentiation
>> - extends SMMUIOTLBPageInvInfo with SEC_SID for invalidation filtering
>> - updates all IOTLB invalidation helpers (smmu_iotlb_inv_iova,
>> smmu_iotlb_inv_ipa, smmu_iotlb_inv_asid_vmid, smmu_iotlb_inv_vmid,
>> smmu_iotlb_inv_vmid_s1) to accept and filter by SEC_SID
>> - plumbs SEC_SID through smmuv3_range_inval for TLB invalidation
>> - enhances trace events to include SEC_SID for better debugging
>>
>> This ensures that secure and non-secure TLB entries are treated as
>> distinct entities within the cache, preventing TLB pollution between
>> different worlds.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmu-common.c | 80 ++++++++++++++++++++++++------------
>> hw/arm/smmu-internal.h | 2 +
>> hw/arm/smmuv3.c | 36 ++++++++--------
>> hw/arm/trace-events | 12 +++---
>> include/hw/arm/smmu-common.h | 16 +++++---
>> 5 files changed, 92 insertions(+), 54 deletions(-)
>>
>> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
>> index 84e71df6767..bb43430cc3b 100644
>> --- a/hw/arm/smmu-common.c
>> +++ b/hw/arm/smmu-common.c
>> @@ -95,7 +95,7 @@ static guint smmu_iotlb_key_hash(gconstpointer v)
>>
>> /* Jenkins hash */
>> a = b = c = JHASH_INITVAL + sizeof(*key);
>> - a += key->asid + key->vmid + key->level + key->tg;
>> + a += key->asid + key->vmid + key->level + key->tg + key->sec_sid;
>> b += extract64(key->iova, 0, 32);
>> c += extract64(key->iova, 32, 32);
>>
>> @@ -111,14 +111,15 @@ static gboolean smmu_iotlb_key_equal(gconstpointer v1, gconstpointer v2)
>>
>> return (k1->asid == k2->asid) && (k1->iova == k2->iova) &&
>> (k1->level == k2->level) && (k1->tg == k2->tg) &&
>> - (k1->vmid == k2->vmid);
>> + (k1->vmid == k2->vmid) && (k1->sec_sid == k2->sec_sid);
>> }
>>
>> SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
>> - uint8_t tg, uint8_t level)
>> + uint8_t tg, uint8_t level,
>> + SMMUSecSID sec_sid)
>> {
>> SMMUIOTLBKey key = {.asid = asid, .vmid = vmid, .iova = iova,
>> - .tg = tg, .level = level};
>> + .tg = tg, .level = level, .sec_sid = sec_sid};
>>
>> return key;
>> }
>> @@ -140,7 +141,7 @@ static SMMUTLBEntry *smmu_iotlb_lookup_all_levels(SMMUState *bs,
>> SMMUIOTLBKey key;
>>
>> key = smmu_get_iotlb_key(cfg->asid, cfg->s2cfg.vmid,
>> - iova & ~mask, tg, level);
>> + iova & ~mask, tg, level, cfg->sec_sid);
>> entry = g_hash_table_lookup(bs->iotlb, &key);
>> if (entry) {
>> break;
>> @@ -204,7 +205,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new)
>> }
>>
>> *key = smmu_get_iotlb_key(cfg->asid, cfg->s2cfg.vmid, new->entry.iova,
>> - tg, new->level);
>> + tg, new->level, cfg->sec_sid);
>> trace_smmu_iotlb_insert(cfg->asid, cfg->s2cfg.vmid, new->entry.iova,
>> tg, new->level);
> Please update all tracepoints with the additional sec_sid. See also
> trace_smmu_iotlb_lookup_hit/miss
Thanks for the review. I'll check all of them.
>
> One question, the spec says in "TLB tagging, VMIDs, ASIDs and
> participation in boradcats TLB maintenance" that cached trasnlations are
> tagged with
> "A translation regime, given by the STE’s StreamWorld and derived in
> part from STE.STRW"
>
> Can you confirm this matches our sec_sid?
For this RFC, my intent was narrower than the full architectural
StreamWorld model. The immediate goal of adding sec_sid to the IOTLB key
was to prevent obvious aliasing between Secure and Non-secure cached
translations in the current implementation, and to make lookup /
invalidation consistently security-state-aware.
Even though in the earlier discussion we clarified that, under the
current sec-sid property framework, a device may effectively have only a
single security state, making the IOTLB key security-state-aware still
avoids unintended aliasing and keeps the behavior consistent with the
intended model.
Strictly speaking, though, I agree this is not yet the full
architectural tagging model. As the spec says, cached translations are
tagged by the translation regime (StreamWorld), with ASID and VMID where
applicable, and StreamWorld is derived from more than just the stream
security state. So sec_sid here should be viewed as a coarse proxy for
the currently implemented subset, not as a claim that we already model
the complete StreamWorld space. I think this deserved more comments
before the whole TLB tagging is implemented. Or we should implment it in
this series?
Best regards,
Tao
>
> Thanks
>
> Eric
>> g_hash_table_insert(bs->iotlb, key, new);
>> @@ -223,26 +224,29 @@ static gboolean smmu_hash_remove_by_asid_vmid(gpointer key, gpointer value,
>> SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
>>
>> return (SMMU_IOTLB_ASID(*iotlb_key) == info->asid) &&
>> - (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid);
>> + (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid) &&
>> + (SMMU_IOTLB_SEC_SID(*iotlb_key) == info->sec_sid);
>> }
>>
>> static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
>> gpointer user_data)
>> {
>> - int vmid = *(int *)user_data;
>> + SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
>> SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
>>
>> - return SMMU_IOTLB_VMID(*iotlb_key) == vmid;
>> + return (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid) &&
>> + (SMMU_IOTLB_SEC_SID(*iotlb_key) == info->sec_sid);
>> }
>>
>> static gboolean smmu_hash_remove_by_vmid_s1(gpointer key, gpointer value,
>> gpointer user_data)
>> {
>> - int vmid = *(int *)user_data;
>> + SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
>> SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
>>
>> - return (SMMU_IOTLB_VMID(*iotlb_key) == vmid) &&
>> - (SMMU_IOTLB_ASID(*iotlb_key) >= 0);
>> + return (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid) &&
>> + (SMMU_IOTLB_ASID(*iotlb_key) >= 0) &&
>> + (SMMU_IOTLB_SEC_SID(*iotlb_key) == info->sec_sid);
>> }
>>
>> static gboolean smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer value,
>> @@ -259,6 +263,9 @@ static gboolean smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer value,
>> if (info->vmid >= 0 && info->vmid != SMMU_IOTLB_VMID(iotlb_key)) {
>> return false;
>> }
>> + if (info->sec_sid != SMMU_IOTLB_SEC_SID(iotlb_key)) {
>> + return false;
>> + }
>> return ((info->iova & ~entry->addr_mask) == entry->iova) ||
>> ((entry->iova & ~info->mask) == info->iova);
>> }
>> @@ -278,6 +285,9 @@ static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
>> if (info->vmid != SMMU_IOTLB_VMID(iotlb_key)) {
>> return false;
>> }
>> + if (info->sec_sid != SMMU_IOTLB_SEC_SID(iotlb_key)) {
>> + return false;
>> + }
>> return ((info->iova & ~entry->addr_mask) == entry->iova) ||
>> ((entry->iova & ~info->mask) == info->iova);
>> }
>> @@ -323,13 +333,15 @@ void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev)
>> }
>>
>> void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
>> - uint8_t tg, uint64_t num_pages, uint8_t ttl)
>> + uint8_t tg, uint64_t num_pages, uint8_t ttl,
>> + SMMUSecSID sec_sid)
>> {
>> /* if tg is not set we use 4KB range invalidation */
>> uint8_t granule = tg ? tg * 2 + 10 : 12;
>>
>> if (ttl && (num_pages == 1) && (asid >= 0)) {
>> - SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, iova, tg, ttl);
>> + SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, iova,
>> + tg, ttl, sec_sid);
>>
>> if (g_hash_table_remove(s->iotlb, &key)) {
>> return;
>> @@ -343,7 +355,8 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
>> SMMUIOTLBPageInvInfo info = {
>> .asid = asid, .iova = iova,
>> .vmid = vmid,
>> - .mask = (num_pages * 1 << granule) - 1};
>> + .mask = (num_pages * 1 << granule) - 1,
>> + .sec_sid = sec_sid};
>>
>> g_hash_table_foreach_remove(s->iotlb,
>> smmu_hash_remove_by_asid_vmid_iova,
>> @@ -355,13 +368,15 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
>> * in Stage-1 invalidation ASID = -1, means don't care.
>> */
>> void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
>> - uint64_t num_pages, uint8_t ttl)
>> + uint64_t num_pages, uint8_t ttl,
>> + SMMUSecSID sec_sid)
>> {
>> uint8_t granule = tg ? tg * 2 + 10 : 12;
>> int asid = -1;
>>
>> if (ttl && (num_pages == 1)) {
>> - SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, ipa, tg, ttl);
>> + SMMUIOTLBKey key = smmu_get_iotlb_key(asid, vmid, ipa,
>> + tg, ttl, sec_sid);
>>
>> if (g_hash_table_remove(s->iotlb, &key)) {
>> return;
>> @@ -371,34 +386,47 @@ void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
>> SMMUIOTLBPageInvInfo info = {
>> .iova = ipa,
>> .vmid = vmid,
>> - .mask = (num_pages << granule) - 1};
>> + .mask = (num_pages << granule) - 1,
>> + .sec_sid = sec_sid};
>>
>> g_hash_table_foreach_remove(s->iotlb,
>> smmu_hash_remove_by_vmid_ipa,
>> &info);
>> }
>>
>> -void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid)
>> +void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid,
>> + SMMUSecSID sec_sid)
>> {
>> SMMUIOTLBPageInvInfo info = {
>> .asid = asid,
>> .vmid = vmid,
>> + .sec_sid = sec_sid,
>> };
>>
>> - trace_smmu_iotlb_inv_asid_vmid(asid, vmid);
>> + trace_smmu_iotlb_inv_asid_vmid(sec_sid, asid, vmid);
>> g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid_vmid, &info);
>> }
>>
>> -void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
>> +void smmu_iotlb_inv_vmid(SMMUState *s, int vmid, SMMUSecSID sec_sid)
>> {
>> - trace_smmu_iotlb_inv_vmid(vmid);
>> - g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
>> + SMMUIOTLBPageInvInfo info = {
>> + .vmid = vmid,
>> + .sec_sid = sec_sid,
>> + };
>> +
>> + trace_smmu_iotlb_inv_vmid(sec_sid, vmid);
>> + g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &info);
>> }
>>
>> -void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
>> +void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid, SMMUSecSID sec_sid)
>> {
>> - trace_smmu_iotlb_inv_vmid_s1(vmid);
>> - g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid_s1, &vmid);
>> + SMMUIOTLBPageInvInfo info = {
>> + .vmid = vmid,
>> + .sec_sid = sec_sid,
>> + };
>> +
>> + trace_smmu_iotlb_inv_vmid_s1(sec_sid, vmid);
>> + g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid_s1, &info);
>> }
>>
>> /* VMSAv8-64 Translation */
>> diff --git a/hw/arm/smmu-internal.h b/hw/arm/smmu-internal.h
>> index a0454f720da..5ddd0372d5b 100644
>> --- a/hw/arm/smmu-internal.h
>> +++ b/hw/arm/smmu-internal.h
>> @@ -145,12 +145,14 @@ static inline int pgd_concat_idx(int start_level, int granule_sz,
>>
>> #define SMMU_IOTLB_ASID(key) ((key).asid)
>> #define SMMU_IOTLB_VMID(key) ((key).vmid)
>> +#define SMMU_IOTLB_SEC_SID(key) ((key).sec_sid)
>>
>> typedef struct SMMUIOTLBPageInvInfo {
>> int asid;
>> int vmid;
>> uint64_t iova;
>> uint64_t mask;
>> + SMMUSecSID sec_sid;
>> } SMMUIOTLBPageInvInfo;
>>
>> #endif
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index 504161ce06d..4a4de719a7c 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -1279,7 +1279,8 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
>> }
>> }
>>
>> -static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
>> +static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
>> + SMMUSecSID sec_sid)
>> {
>> dma_addr_t end, addr = CMD_ADDR(cmd);
>> uint8_t type = CMD_TYPE(cmd);
>> @@ -1304,12 +1305,13 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
>> }
>>
>> if (!tg) {
>> - trace_smmuv3_range_inval(vmid, asid, addr, tg, 1, ttl, leaf, stage);
>> + trace_smmuv3_range_inval(sec_sid, vmid, asid, addr,
>> + tg, 1, ttl, leaf, stage);
>> smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage);
>> if (stage == SMMU_STAGE_1) {
>> - smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl);
>> + smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl, sec_sid);
>> } else {
>> - smmu_iotlb_inv_ipa(s, vmid, addr, tg, 1, ttl);
>> + smmu_iotlb_inv_ipa(s, vmid, addr, tg, 1, ttl, sec_sid);
>> }
>> return;
>> }
>> @@ -1326,13 +1328,15 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
>> uint64_t mask = dma_aligned_pow2_mask(addr, end, 64);
>>
>> num_pages = (mask + 1) >> granule;
>> - trace_smmuv3_range_inval(vmid, asid, addr, tg, num_pages,
>> - ttl, leaf, stage);
>> - smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, num_pages, stage);
>> + trace_smmuv3_range_inval(sec_sid, vmid, asid, addr, tg,
>> + num_pages, ttl, leaf, stage);
>> + smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg,
>> + num_pages, stage);
>> if (stage == SMMU_STAGE_1) {
>> - smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, num_pages, ttl);
>> + smmu_iotlb_inv_iova(s, asid, vmid, addr, tg,
>> + num_pages, ttl, sec_sid);
>> } else {
>> - smmu_iotlb_inv_ipa(s, vmid, addr, tg, num_pages, ttl);
>> + smmu_iotlb_inv_ipa(s, vmid, addr, tg, num_pages, ttl, sec_sid);
>> }
>> addr += mask + 1;
>> }
>> @@ -1474,9 +1478,9 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
>> vmid = CMD_VMID(&cmd);
>> }
>>
>> - trace_smmuv3_cmdq_tlbi_nh_asid(asid);
>> + trace_smmuv3_cmdq_tlbi_nh_asid(sec_sid, asid);
>> smmu_inv_notifiers_all(&s->smmu_state);
>> - smmu_iotlb_inv_asid_vmid(bs, asid, vmid);
>> + smmu_iotlb_inv_asid_vmid(bs, asid, vmid, sec_sid);
>> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
>> cmd_error = SMMU_CERROR_ILL;
>> break;
>> @@ -1498,8 +1502,8 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
>> */
>> if (STAGE2_SUPPORTED(s)) {
>> vmid = CMD_VMID(&cmd);
>> - trace_smmuv3_cmdq_tlbi_nh(vmid);
>> - smmu_iotlb_inv_vmid_s1(bs, vmid);
>> + trace_smmuv3_cmdq_tlbi_nh(sec_sid, vmid);
>> + smmu_iotlb_inv_vmid_s1(bs, vmid, sec_sid);
>> break;
>> }
>> QEMU_FALLTHROUGH;
>> @@ -1519,7 +1523,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
>> cmd_error = SMMU_CERROR_ILL;
>> break;
>> }
>> - smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1);
>> + smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1, SMMU_SEC_SID_NS);
>> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
>> cmd_error = SMMU_CERROR_ILL;
>> break;
>> @@ -1536,7 +1540,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
>>
>> trace_smmuv3_cmdq_tlbi_s12_vmid(vmid);
>> smmu_inv_notifiers_all(&s->smmu_state);
>> - smmu_iotlb_inv_vmid(bs, vmid);
>> + smmu_iotlb_inv_vmid(bs, vmid, SMMU_SEC_SID_NS);
>> break;
>> }
>> case SMMU_CMD_TLBI_S2_IPA:
>> @@ -1548,7 +1552,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
>> * As currently only either s1 or s2 are supported
>> * we can reuse same function for s2.
>> */
>> - smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2);
>> + smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2, SMMU_SEC_SID_NS);
>> break;
>> case SMMU_CMD_ATC_INV:
>> {
>> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
>> index 9c2cc131ab4..4e360b3c0d3 100644
>> --- a/hw/arm/trace-events
>> +++ b/hw/arm/trace-events
>> @@ -18,9 +18,9 @@ smmu_ptw_page_pte(int stage, int level, uint64_t iova, uint64_t baseaddr, uint6
>> smmu_ptw_block_pte(int stage, int level, uint64_t baseaddr, uint64_t pteaddr, uint64_t pte, uint64_t iova, uint64_t gpa, int bsize_mb) "stage=%d level=%d base@=0x%"PRIx64" pte@=0x%"PRIx64" pte=0x%"PRIx64" iova=0x%"PRIx64" block address = 0x%"PRIx64" block size = %d MiB"
>> smmu_get_pte(uint64_t baseaddr, int index, uint64_t pteaddr, uint64_t pte) "baseaddr=0x%"PRIx64" index=0x%x, pteaddr=0x%"PRIx64", pte=0x%"PRIx64
>> smmu_iotlb_inv_all(void) "IOTLB invalidate all"
>> -smmu_iotlb_inv_asid_vmid(int asid, int vmid) "IOTLB invalidate asid=%d vmid=%d"
>> -smmu_iotlb_inv_vmid(int vmid) "IOTLB invalidate vmid=%d"
>> -smmu_iotlb_inv_vmid_s1(int vmid) "IOTLB invalidate vmid=%d"
>> +smmu_iotlb_inv_asid_vmid(int sec_sid, int asid, int vmid) "IOTLB invalidate sec_sid=%d asid=%d vmid=%d"
>> +smmu_iotlb_inv_vmid(int sec_sid, int vmid) "IOTLB invalidate sec_sid=%d vmid=%d"
>> +smmu_iotlb_inv_vmid_s1(int sec_sid, int vmid) "IOTLB invalidate S1 sec_sid=%d vmid=%d"
>> smmu_iotlb_inv_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
>> smmu_configs_inv_sid_range(uint32_t start, uint32_t end) "Config cache INV SID range from 0x%x to 0x%x"
>> smmu_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
>> @@ -56,10 +56,10 @@ smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%x - end=0x%x"
>> smmuv3_cmdq_cfgi_cd(uint32_t sid) "sid=0x%x"
>> smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
>> smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
>> -smmuv3_range_inval(int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf, int stage) "vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d stage=%d"
>> -smmuv3_cmdq_tlbi_nh(int vmid) "vmid=%d"
>> +smmuv3_range_inval(int sec_sid, int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf, int stage) "sec_sid=%d vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d stage=%d"
>> +smmuv3_cmdq_tlbi_nh(int sec_sid, int vmid) "sec_sid=%d vmid=%d"
>> smmuv3_cmdq_tlbi_nsnh(void) ""
>> -smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
>> +smmuv3_cmdq_tlbi_nh_asid(int sec_sid, int asid) "sec_sid=%d asid=%d"
>> smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
>> smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s"
>> smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s"
>> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
>> index b0a02e12fe6..7d1d0936921 100644
>> --- a/include/hw/arm/smmu-common.h
>> +++ b/include/hw/arm/smmu-common.h
>> @@ -162,6 +162,7 @@ typedef struct SMMUIOTLBKey {
>> int vmid;
>> uint8_t tg;
>> uint8_t level;
>> + SMMUSecSID sec_sid;
>> } SMMUIOTLBKey;
>>
>> typedef struct SMMUConfigKey {
>> @@ -256,16 +257,19 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
>> SMMUTransTableInfo *tt, hwaddr iova);
>> void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *entry);
>> SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
>> - uint8_t tg, uint8_t level);
>> + uint8_t tg, uint8_t level, SMMUSecSID sec_sid);
>> SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID sec_sid);
>> void smmu_iotlb_inv_all(SMMUState *s);
>> -void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid);
>> -void smmu_iotlb_inv_vmid(SMMUState *s, int vmid);
>> -void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid);
>> +void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid,
>> + SMMUSecSID sec_sid);
>> +void smmu_iotlb_inv_vmid(SMMUState *s, int vmid, SMMUSecSID sec_sid);
>> +void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid, SMMUSecSID sec_sid);
>> void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
>> - uint8_t tg, uint64_t num_pages, uint8_t ttl);
>> + uint8_t tg, uint64_t num_pages, uint8_t ttl,
>> + SMMUSecSID sec_sid);
>> void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
>> - uint64_t num_pages, uint8_t ttl);
>> + uint64_t num_pages, uint8_t ttl,
>> + SMMUSecSID sec_sid);
>> void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range);
>> void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev);
>> /* Unmap the range of all the notifiers registered to any IOMMU mr */
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (14 preceding siblings ...)
2026-02-21 10:16 ` [RFC v4 15/31] hw/arm/smmuv3: Tag IOTLB cache keys with SEC_SID Tao Tang
@ 2026-02-21 10:17 ` Tao Tang
2026-02-25 21:32 ` Pierrick Bouvier
2026-02-27 14:47 ` Mostafa Saleh
2026-02-21 10:17 ` [RFC v4 17/31] hw/arm/smmuv3: Pass sec_sid into cmdq consume path Tao Tang
` (14 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:17 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Extend IOMMU notifier functions to be SEC_SID-aware, ensuring that
invalidation notifications are dispatched to the correct security-aware
address space.
This ensures IOMMU notifier events (e.g., to VFIO) are correctly routed
to the appropriate security world's address space, maintaining isolation
between secure and non-secure DMA operations.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 18 +++++++++++-------
1 file changed, 11 insertions(+), 7 deletions(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 4a4de719a7c..e33a7babd1c 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1195,15 +1195,16 @@ epilogue:
* @tg: translation granule (if communicated through range invalidation)
* @num_pages: number of @granule sized pages (if tg != 0), otherwise 1
* @stage: Which stage(1 or 2) is used
+ * @sec_sid: StreamID Security state
*/
static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
IOMMUNotifier *n,
int asid, int vmid,
dma_addr_t iova, uint8_t tg,
- uint64_t num_pages, int stage)
+ uint64_t num_pages, int stage,
+ SMMUSecSID sec_sid)
{
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
.inval_ste_allowed = true};
SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo, sec_sid);
@@ -1251,7 +1252,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
}
event.type = IOMMU_NOTIFIER_UNMAP;
- event.entry.target_as = &address_space_memory;
+ event.entry.target_as = smmu_get_address_space(sdev->smmu, sec_sid);
+ g_assert(event.entry.target_as);
event.entry.iova = iova;
event.entry.addr_mask = num_pages * (1 << granule) - 1;
event.entry.perm = IOMMU_NONE;
@@ -1262,7 +1264,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
/* invalidate an asid/vmid/iova range tuple in all mr's */
static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
dma_addr_t iova, uint8_t tg,
- uint64_t num_pages, int stage)
+ uint64_t num_pages, int stage,
+ SMMUSecSID sec_sid)
{
SMMUDevice *sdev;
@@ -1274,7 +1277,8 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
iova, tg, num_pages, stage);
IOMMU_NOTIFIER_FOREACH(n, mr) {
- smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages, stage);
+ smmuv3_notify_iova(mr, n, asid, vmid, iova, tg,
+ num_pages, stage, sec_sid);
}
}
}
@@ -1307,7 +1311,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
if (!tg) {
trace_smmuv3_range_inval(sec_sid, vmid, asid, addr,
tg, 1, ttl, leaf, stage);
- smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage);
+ smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage, sec_sid);
if (stage == SMMU_STAGE_1) {
smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl, sec_sid);
} else {
@@ -1331,7 +1335,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
trace_smmuv3_range_inval(sec_sid, vmid, asid, addr, tg,
num_pages, ttl, leaf, stage);
smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg,
- num_pages, stage);
+ num_pages, stage, sec_sid);
if (stage == SMMU_STAGE_1) {
smmu_iotlb_inv_iova(s, asid, vmid, addr, tg,
num_pages, ttl, sec_sid);
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path
2026-02-21 10:17 ` [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path Tao Tang
@ 2026-02-25 21:32 ` Pierrick Bouvier
2026-02-27 14:47 ` Mostafa Saleh
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:32 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:17 AM, Tao Tang wrote:
> Extend IOMMU notifier functions to be SEC_SID-aware, ensuring that
> invalidation notifications are dispatched to the correct security-aware
> address space.
>
> This ensures IOMMU notifier events (e.g., to VFIO) are correctly routed
> to the appropriate security world's address space, maintaining isolation
> between secure and non-secure DMA operations.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 18 +++++++++++-------
> 1 file changed, 11 insertions(+), 7 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path
2026-02-21 10:17 ` [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path Tao Tang
2026-02-25 21:32 ` Pierrick Bouvier
@ 2026-02-27 14:47 ` Mostafa Saleh
2026-03-01 15:26 ` Tao Tang
2026-03-02 18:26 ` Eric Auger
1 sibling, 2 replies; 136+ messages in thread
From: Mostafa Saleh @ 2026-02-27 14:47 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sat, Feb 21, 2026 at 06:17:06PM +0800, Tao Tang wrote:
> Extend IOMMU notifier functions to be SEC_SID-aware, ensuring that
> invalidation notifications are dispatched to the correct security-aware
> address space.
>
> This ensures IOMMU notifier events (e.g., to VFIO) are correctly routed
> to the appropriate security world's address space, maintaining isolation
> between secure and non-secure DMA operations.
I don’t think that VFIO cares about secure regime, my guess is to
keep the functions as this and don’t call them for secure invalidations.
Thanks,
Mostafa
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 18 +++++++++++-------
> 1 file changed, 11 insertions(+), 7 deletions(-)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 4a4de719a7c..e33a7babd1c 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1195,15 +1195,16 @@ epilogue:
> * @tg: translation granule (if communicated through range invalidation)
> * @num_pages: number of @granule sized pages (if tg != 0), otherwise 1
> * @stage: Which stage(1 or 2) is used
> + * @sec_sid: StreamID Security state
> */
> static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> IOMMUNotifier *n,
> int asid, int vmid,
> dma_addr_t iova, uint8_t tg,
> - uint64_t num_pages, int stage)
> + uint64_t num_pages, int stage,
> + SMMUSecSID sec_sid)
> {
> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
> .inval_ste_allowed = true};
> SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo, sec_sid);
> @@ -1251,7 +1252,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> }
>
> event.type = IOMMU_NOTIFIER_UNMAP;
> - event.entry.target_as = &address_space_memory;
> + event.entry.target_as = smmu_get_address_space(sdev->smmu, sec_sid);
> + g_assert(event.entry.target_as);
> event.entry.iova = iova;
> event.entry.addr_mask = num_pages * (1 << granule) - 1;
> event.entry.perm = IOMMU_NONE;
> @@ -1262,7 +1264,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> /* invalidate an asid/vmid/iova range tuple in all mr's */
> static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
> dma_addr_t iova, uint8_t tg,
> - uint64_t num_pages, int stage)
> + uint64_t num_pages, int stage,
> + SMMUSecSID sec_sid)
> {
> SMMUDevice *sdev;
>
> @@ -1274,7 +1277,8 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
> iova, tg, num_pages, stage);
>
> IOMMU_NOTIFIER_FOREACH(n, mr) {
> - smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages, stage);
> + smmuv3_notify_iova(mr, n, asid, vmid, iova, tg,
> + num_pages, stage, sec_sid);
> }
> }
> }
> @@ -1307,7 +1311,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
> if (!tg) {
> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr,
> tg, 1, ttl, leaf, stage);
> - smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage);
> + smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage, sec_sid);
> if (stage == SMMU_STAGE_1) {
> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl, sec_sid);
> } else {
> @@ -1331,7 +1335,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr, tg,
> num_pages, ttl, leaf, stage);
> smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg,
> - num_pages, stage);
> + num_pages, stage, sec_sid);
> if (stage == SMMU_STAGE_1) {
> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg,
> num_pages, ttl, sec_sid);
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path
2026-02-27 14:47 ` Mostafa Saleh
@ 2026-03-01 15:26 ` Tao Tang
2026-03-02 18:26 ` Eric Auger
1 sibling, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-01 15:26 UTC (permalink / raw)
To: Mostafa Saleh
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
Hi Mostafa,
On 2026/2/27 PM10:47, Mostafa Saleh wrote:
> On Sat, Feb 21, 2026 at 06:17:06PM +0800, Tao Tang wrote:
>> Extend IOMMU notifier functions to be SEC_SID-aware, ensuring that
>> invalidation notifications are dispatched to the correct security-aware
>> address space.
>>
>> This ensures IOMMU notifier events (e.g., to VFIO) are correctly routed
>> to the appropriate security world's address space, maintaining isolation
>> between secure and non-secure DMA operations.
> I don’t think that VFIO cares about secure regime, my guess is to
> keep the functions as this and don’t call them for secure invalidations.
>
> Thanks,
> Mostafa
Agreed. I'll remove the changes in this commit in V5.
Best regards,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path
2026-02-27 14:47 ` Mostafa Saleh
2026-03-01 15:26 ` Tao Tang
@ 2026-03-02 18:26 ` Eric Auger
2026-03-02 19:17 ` Mostafa Saleh
1 sibling, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-02 18:26 UTC (permalink / raw)
To: Mostafa Saleh, Tao Tang
Cc: Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum, qemu-devel,
qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On 2/27/26 3:47 PM, Mostafa Saleh wrote:
> On Sat, Feb 21, 2026 at 06:17:06PM +0800, Tao Tang wrote:
>> Extend IOMMU notifier functions to be SEC_SID-aware, ensuring that
>> invalidation notifications are dispatched to the correct security-aware
>> address space.
>>
>> This ensures IOMMU notifier events (e.g., to VFIO) are correctly routed
>> to the appropriate security world's address space, maintaining isolation
>> between secure and non-secure DMA operations.
> I don’t think that VFIO cares about secure regime, my guess is to
> keep the functions as this and don’t call them for secure invalidations.
So do we want to prevent VFIO devices from working in secure mode along
with the SMMU?
Eric
>
> Thanks,
> Mostafa
>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmuv3.c | 18 +++++++++++-------
>> 1 file changed, 11 insertions(+), 7 deletions(-)
>>
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index 4a4de719a7c..e33a7babd1c 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -1195,15 +1195,16 @@ epilogue:
>> * @tg: translation granule (if communicated through range invalidation)
>> * @num_pages: number of @granule sized pages (if tg != 0), otherwise 1
>> * @stage: Which stage(1 or 2) is used
>> + * @sec_sid: StreamID Security state
>> */
>> static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>> IOMMUNotifier *n,
>> int asid, int vmid,
>> dma_addr_t iova, uint8_t tg,
>> - uint64_t num_pages, int stage)
>> + uint64_t num_pages, int stage,
>> + SMMUSecSID sec_sid)
>> {
>> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
>> .inval_ste_allowed = true};
>> SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo, sec_sid);
>> @@ -1251,7 +1252,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>> }
>>
>> event.type = IOMMU_NOTIFIER_UNMAP;
>> - event.entry.target_as = &address_space_memory;
>> + event.entry.target_as = smmu_get_address_space(sdev->smmu, sec_sid);
>> + g_assert(event.entry.target_as);
>> event.entry.iova = iova;
>> event.entry.addr_mask = num_pages * (1 << granule) - 1;
>> event.entry.perm = IOMMU_NONE;
>> @@ -1262,7 +1264,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>> /* invalidate an asid/vmid/iova range tuple in all mr's */
>> static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
>> dma_addr_t iova, uint8_t tg,
>> - uint64_t num_pages, int stage)
>> + uint64_t num_pages, int stage,
>> + SMMUSecSID sec_sid)
>> {
>> SMMUDevice *sdev;
>>
>> @@ -1274,7 +1277,8 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
>> iova, tg, num_pages, stage);
>>
>> IOMMU_NOTIFIER_FOREACH(n, mr) {
>> - smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages, stage);
>> + smmuv3_notify_iova(mr, n, asid, vmid, iova, tg,
>> + num_pages, stage, sec_sid);
>> }
>> }
>> }
>> @@ -1307,7 +1311,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
>> if (!tg) {
>> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr,
>> tg, 1, ttl, leaf, stage);
>> - smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage);
>> + smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage, sec_sid);
>> if (stage == SMMU_STAGE_1) {
>> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl, sec_sid);
>> } else {
>> @@ -1331,7 +1335,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
>> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr, tg,
>> num_pages, ttl, leaf, stage);
>> smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg,
>> - num_pages, stage);
>> + num_pages, stage, sec_sid);
>> if (stage == SMMU_STAGE_1) {
>> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg,
>> num_pages, ttl, sec_sid);
>> --
>> 2.34.1
>>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path
2026-03-02 18:26 ` Eric Auger
@ 2026-03-02 19:17 ` Mostafa Saleh
2026-03-03 7:49 ` Eric Auger
0 siblings, 1 reply; 136+ messages in thread
From: Mostafa Saleh @ 2026-03-02 19:17 UTC (permalink / raw)
To: Eric Auger
Cc: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Mon, Mar 02, 2026 at 07:26:10PM +0100, Eric Auger wrote:
>
>
> On 2/27/26 3:47 PM, Mostafa Saleh wrote:
> > On Sat, Feb 21, 2026 at 06:17:06PM +0800, Tao Tang wrote:
> >> Extend IOMMU notifier functions to be SEC_SID-aware, ensuring that
> >> invalidation notifications are dispatched to the correct security-aware
> >> address space.
> >>
> >> This ensures IOMMU notifier events (e.g., to VFIO) are correctly routed
> >> to the appropriate security world's address space, maintaining isolation
> >> between secure and non-secure DMA operations.
> > I don’t think that VFIO cares about secure regime, my guess is to
> > keep the functions as this and don’t call them for secure invalidations.
>
> So do we want to prevent VFIO devices from working in secure mode along
> with the SMMU?
Yes, my impression was that VFIO only works with NS devices, for example
I see vfio_iommu_map_notify() only deals with system memory:
if (iotlb->target_as != &address_space_memory) {
error_setg(&local_err,
"Wrong target AS \"%s\", only system memory is allowed",
Otherwise, the callback needs to be enlighted by different address
spaces, I am not sure how (and what uses cases?) will that be done, does
QEMU emulate TZ in that case? (and present some devices as secure?)
Thanks,
Mostafa
>
> Eric
> >
> > Thanks,
> > Mostafa
> >
> >> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> >> ---
> >> hw/arm/smmuv3.c | 18 +++++++++++-------
> >> 1 file changed, 11 insertions(+), 7 deletions(-)
> >>
> >> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> >> index 4a4de719a7c..e33a7babd1c 100644
> >> --- a/hw/arm/smmuv3.c
> >> +++ b/hw/arm/smmuv3.c
> >> @@ -1195,15 +1195,16 @@ epilogue:
> >> * @tg: translation granule (if communicated through range invalidation)
> >> * @num_pages: number of @granule sized pages (if tg != 0), otherwise 1
> >> * @stage: Which stage(1 or 2) is used
> >> + * @sec_sid: StreamID Security state
> >> */
> >> static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> >> IOMMUNotifier *n,
> >> int asid, int vmid,
> >> dma_addr_t iova, uint8_t tg,
> >> - uint64_t num_pages, int stage)
> >> + uint64_t num_pages, int stage,
> >> + SMMUSecSID sec_sid)
> >> {
> >> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
> >> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> >> SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
> >> .inval_ste_allowed = true};
> >> SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo, sec_sid);
> >> @@ -1251,7 +1252,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> >> }
> >>
> >> event.type = IOMMU_NOTIFIER_UNMAP;
> >> - event.entry.target_as = &address_space_memory;
> >> + event.entry.target_as = smmu_get_address_space(sdev->smmu, sec_sid);
> >> + g_assert(event.entry.target_as);
> >> event.entry.iova = iova;
> >> event.entry.addr_mask = num_pages * (1 << granule) - 1;
> >> event.entry.perm = IOMMU_NONE;
> >> @@ -1262,7 +1264,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> >> /* invalidate an asid/vmid/iova range tuple in all mr's */
> >> static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
> >> dma_addr_t iova, uint8_t tg,
> >> - uint64_t num_pages, int stage)
> >> + uint64_t num_pages, int stage,
> >> + SMMUSecSID sec_sid)
> >> {
> >> SMMUDevice *sdev;
> >>
> >> @@ -1274,7 +1277,8 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
> >> iova, tg, num_pages, stage);
> >>
> >> IOMMU_NOTIFIER_FOREACH(n, mr) {
> >> - smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages, stage);
> >> + smmuv3_notify_iova(mr, n, asid, vmid, iova, tg,
> >> + num_pages, stage, sec_sid);
> >> }
> >> }
> >> }
> >> @@ -1307,7 +1311,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
> >> if (!tg) {
> >> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr,
> >> tg, 1, ttl, leaf, stage);
> >> - smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage);
> >> + smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage, sec_sid);
> >> if (stage == SMMU_STAGE_1) {
> >> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl, sec_sid);
> >> } else {
> >> @@ -1331,7 +1335,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
> >> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr, tg,
> >> num_pages, ttl, leaf, stage);
> >> smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg,
> >> - num_pages, stage);
> >> + num_pages, stage, sec_sid);
> >> if (stage == SMMU_STAGE_1) {
> >> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg,
> >> num_pages, ttl, sec_sid);
> >> --
> >> 2.34.1
> >>
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path
2026-03-02 19:17 ` Mostafa Saleh
@ 2026-03-03 7:49 ` Eric Auger
2026-03-04 15:34 ` Tao Tang
0 siblings, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-03 7:49 UTC (permalink / raw)
To: Mostafa Saleh
Cc: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
Hi Mostafa,
On 3/2/26 8:17 PM, Mostafa Saleh wrote:
> On Mon, Mar 02, 2026 at 07:26:10PM +0100, Eric Auger wrote:
>>
>> On 2/27/26 3:47 PM, Mostafa Saleh wrote:
>>> On Sat, Feb 21, 2026 at 06:17:06PM +0800, Tao Tang wrote:
>>>> Extend IOMMU notifier functions to be SEC_SID-aware, ensuring that
>>>> invalidation notifications are dispatched to the correct security-aware
>>>> address space.
>>>>
>>>> This ensures IOMMU notifier events (e.g., to VFIO) are correctly routed
>>>> to the appropriate security world's address space, maintaining isolation
>>>> between secure and non-secure DMA operations.
>>> I don’t think that VFIO cares about secure regime, my guess is to
>>> keep the functions as this and don’t call them for secure invalidations.
>> So do we want to prevent VFIO devices from working in secure mode along
>> with the SMMU?
> Yes, my impression was that VFIO only works with NS devices, for example
> I see vfio_iommu_map_notify() only deals with system memory:
>
> if (iotlb->target_as != &address_space_memory) {
> error_setg(&local_err,
> "Wrong target AS \"%s\", only system memory is allowed",
Indeed this would need to be changed. I am totally fine not supporting
VFIO nor vhost devices (which also use unmap notifiers) in secure more.
However in that case I think the series would need to properly check
that those devices are not used in secure regime.
Thanks
Eric
>
>
> Otherwise, the callback needs to be enlighted by different address
> spaces, I am not sure how (and what uses cases?) will that be done, does
> QEMU emulate TZ in that case? (and present some devices as secure?)
>
> Thanks,
> Mostafa
>
>> Eric
>>> Thanks,
>>> Mostafa
>>>
>>>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>>>> ---
>>>> hw/arm/smmuv3.c | 18 +++++++++++-------
>>>> 1 file changed, 11 insertions(+), 7 deletions(-)
>>>>
>>>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>>>> index 4a4de719a7c..e33a7babd1c 100644
>>>> --- a/hw/arm/smmuv3.c
>>>> +++ b/hw/arm/smmuv3.c
>>>> @@ -1195,15 +1195,16 @@ epilogue:
>>>> * @tg: translation granule (if communicated through range invalidation)
>>>> * @num_pages: number of @granule sized pages (if tg != 0), otherwise 1
>>>> * @stage: Which stage(1 or 2) is used
>>>> + * @sec_sid: StreamID Security state
>>>> */
>>>> static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>>> IOMMUNotifier *n,
>>>> int asid, int vmid,
>>>> dma_addr_t iova, uint8_t tg,
>>>> - uint64_t num_pages, int stage)
>>>> + uint64_t num_pages, int stage,
>>>> + SMMUSecSID sec_sid)
>>>> {
>>>> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
>>>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>>> SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
>>>> .inval_ste_allowed = true};
>>>> SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo, sec_sid);
>>>> @@ -1251,7 +1252,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>>> }
>>>>
>>>> event.type = IOMMU_NOTIFIER_UNMAP;
>>>> - event.entry.target_as = &address_space_memory;
>>>> + event.entry.target_as = smmu_get_address_space(sdev->smmu, sec_sid);
>>>> + g_assert(event.entry.target_as);
>>>> event.entry.iova = iova;
>>>> event.entry.addr_mask = num_pages * (1 << granule) - 1;
>>>> event.entry.perm = IOMMU_NONE;
>>>> @@ -1262,7 +1264,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>>> /* invalidate an asid/vmid/iova range tuple in all mr's */
>>>> static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
>>>> dma_addr_t iova, uint8_t tg,
>>>> - uint64_t num_pages, int stage)
>>>> + uint64_t num_pages, int stage,
>>>> + SMMUSecSID sec_sid)
>>>> {
>>>> SMMUDevice *sdev;
>>>>
>>>> @@ -1274,7 +1277,8 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
>>>> iova, tg, num_pages, stage);
>>>>
>>>> IOMMU_NOTIFIER_FOREACH(n, mr) {
>>>> - smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages, stage);
>>>> + smmuv3_notify_iova(mr, n, asid, vmid, iova, tg,
>>>> + num_pages, stage, sec_sid);
>>>> }
>>>> }
>>>> }
>>>> @@ -1307,7 +1311,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
>>>> if (!tg) {
>>>> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr,
>>>> tg, 1, ttl, leaf, stage);
>>>> - smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage);
>>>> + smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage, sec_sid);
>>>> if (stage == SMMU_STAGE_1) {
>>>> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl, sec_sid);
>>>> } else {
>>>> @@ -1331,7 +1335,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
>>>> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr, tg,
>>>> num_pages, ttl, leaf, stage);
>>>> smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg,
>>>> - num_pages, stage);
>>>> + num_pages, stage, sec_sid);
>>>> if (stage == SMMU_STAGE_1) {
>>>> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg,
>>>> num_pages, ttl, sec_sid);
>>>> --
>>>> 2.34.1
>>>>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path
2026-03-03 7:49 ` Eric Auger
@ 2026-03-04 15:34 ` Tao Tang
2026-03-04 16:36 ` Eric Auger
0 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-03-04 15:34 UTC (permalink / raw)
To: eric.auger, Mostafa Saleh
Cc: Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum, qemu-devel,
qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
Hi all,
On 2026/3/3 PM3:49, Eric Auger wrote:
> Hi Mostafa,
>
> On 3/2/26 8:17 PM, Mostafa Saleh wrote:
>> On Mon, Mar 02, 2026 at 07:26:10PM +0100, Eric Auger wrote:
>>> On 2/27/26 3:47 PM, Mostafa Saleh wrote:
>>>> On Sat, Feb 21, 2026 at 06:17:06PM +0800, Tao Tang wrote:
>>>>> Extend IOMMU notifier functions to be SEC_SID-aware, ensuring that
>>>>> invalidation notifications are dispatched to the correct security-aware
>>>>> address space.
>>>>>
>>>>> This ensures IOMMU notifier events (e.g., to VFIO) are correctly routed
>>>>> to the appropriate security world's address space, maintaining isolation
>>>>> between secure and non-secure DMA operations.
>>>> I don’t think that VFIO cares about secure regime, my guess is to
>>>> keep the functions as this and don’t call them for secure invalidations.
>>> So do we want to prevent VFIO devices from working in secure mode along
>>> with the SMMU?
>> Yes, my impression was that VFIO only works with NS devices, for example
>> I see vfio_iommu_map_notify() only deals with system memory:
>>
>> if (iotlb->target_as != &address_space_memory) {
>> error_setg(&local_err,
>> "Wrong target AS \"%s\", only system memory is allowed",
> Indeed this would need to be changed. I am totally fine not supporting
> VFIO nor vhost devices (which also use unmap notifiers) in secure more.
> However in that case I think the series would need to properly check
> that those devices are not used in secure regime.
Thanks for the clarification.
For this series, I’m fine not supporting VFIO/vhost in Secure regime.
I’ll add a fail-fast check at smmuv3_inv_notifiers_iova to reject
devices using IOMMU notifiers when the selected regime is non-NS. The NS
path stays unchanged.
/* invalidate an asid/vmid/iova range tuple in all mr's */
static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
dma_addr_t iova, uint8_t tg,
uint64_t num_pages, int stage,
SMMUSecSID sec_sid)
{
SMMUDevice *sdev;
if (sec_sid != SMMU_SEC_SID_NS) { // fail-fast check
return;
}
......
}
Best regards,
Tao
>
> Thanks
>
> Eric
>>
>> Otherwise, the callback needs to be enlighted by different address
>> spaces, I am not sure how (and what uses cases?) will that be done, does
>> QEMU emulate TZ in that case? (and present some devices as secure?)
>>
>> Thanks,
>> Mostafa
>>
>>> Eric
>>>> Thanks,
>>>> Mostafa
>>>>
>>>>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>>>>> ---
>>>>> hw/arm/smmuv3.c | 18 +++++++++++-------
>>>>> 1 file changed, 11 insertions(+), 7 deletions(-)
>>>>>
>>>>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>>>>> index 4a4de719a7c..e33a7babd1c 100644
>>>>> --- a/hw/arm/smmuv3.c
>>>>> +++ b/hw/arm/smmuv3.c
>>>>> @@ -1195,15 +1195,16 @@ epilogue:
>>>>> * @tg: translation granule (if communicated through range invalidation)
>>>>> * @num_pages: number of @granule sized pages (if tg != 0), otherwise 1
>>>>> * @stage: Which stage(1 or 2) is used
>>>>> + * @sec_sid: StreamID Security state
>>>>> */
>>>>> static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>>>> IOMMUNotifier *n,
>>>>> int asid, int vmid,
>>>>> dma_addr_t iova, uint8_t tg,
>>>>> - uint64_t num_pages, int stage)
>>>>> + uint64_t num_pages, int stage,
>>>>> + SMMUSecSID sec_sid)
>>>>> {
>>>>> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
>>>>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>>>> SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
>>>>> .inval_ste_allowed = true};
>>>>> SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo, sec_sid);
>>>>> @@ -1251,7 +1252,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>>>> }
>>>>>
>>>>> event.type = IOMMU_NOTIFIER_UNMAP;
>>>>> - event.entry.target_as = &address_space_memory;
>>>>> + event.entry.target_as = smmu_get_address_space(sdev->smmu, sec_sid);
>>>>> + g_assert(event.entry.target_as);
>>>>> event.entry.iova = iova;
>>>>> event.entry.addr_mask = num_pages * (1 << granule) - 1;
>>>>> event.entry.perm = IOMMU_NONE;
>>>>> @@ -1262,7 +1264,8 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>>>> /* invalidate an asid/vmid/iova range tuple in all mr's */
>>>>> static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
>>>>> dma_addr_t iova, uint8_t tg,
>>>>> - uint64_t num_pages, int stage)
>>>>> + uint64_t num_pages, int stage,
>>>>> + SMMUSecSID sec_sid)
>>>>> {
>>>>> SMMUDevice *sdev;
>>>>>
>>>>> @@ -1274,7 +1277,8 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
>>>>> iova, tg, num_pages, stage);
>>>>>
>>>>> IOMMU_NOTIFIER_FOREACH(n, mr) {
>>>>> - smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages, stage);
>>>>> + smmuv3_notify_iova(mr, n, asid, vmid, iova, tg,
>>>>> + num_pages, stage, sec_sid);
>>>>> }
>>>>> }
>>>>> }
>>>>> @@ -1307,7 +1311,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
>>>>> if (!tg) {
>>>>> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr,
>>>>> tg, 1, ttl, leaf, stage);
>>>>> - smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage);
>>>>> + smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1, stage, sec_sid);
>>>>> if (stage == SMMU_STAGE_1) {
>>>>> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl, sec_sid);
>>>>> } else {
>>>>> @@ -1331,7 +1335,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
>>>>> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr, tg,
>>>>> num_pages, ttl, leaf, stage);
>>>>> smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg,
>>>>> - num_pages, stage);
>>>>> + num_pages, stage, sec_sid);
>>>>> if (stage == SMMU_STAGE_1) {
>>>>> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg,
>>>>> num_pages, ttl, sec_sid);
>>>>> --
>>>>> 2.34.1
>>>>>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path
2026-03-04 15:34 ` Tao Tang
@ 2026-03-04 16:36 ` Eric Auger
0 siblings, 0 replies; 136+ messages in thread
From: Eric Auger @ 2026-03-04 16:36 UTC (permalink / raw)
To: Tao Tang, Mostafa Saleh
Cc: Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum, qemu-devel,
qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On 3/4/26 4:34 PM, Tao Tang wrote:
> Hi all,
>
> On 2026/3/3 PM3:49, Eric Auger wrote:
>> Hi Mostafa,
>>
>> On 3/2/26 8:17 PM, Mostafa Saleh wrote:
>>> On Mon, Mar 02, 2026 at 07:26:10PM +0100, Eric Auger wrote:
>>>> On 2/27/26 3:47 PM, Mostafa Saleh wrote:
>>>>> On Sat, Feb 21, 2026 at 06:17:06PM +0800, Tao Tang wrote:
>>>>>> Extend IOMMU notifier functions to be SEC_SID-aware, ensuring that
>>>>>> invalidation notifications are dispatched to the correct
>>>>>> security-aware
>>>>>> address space.
>>>>>>
>>>>>> This ensures IOMMU notifier events (e.g., to VFIO) are correctly
>>>>>> routed
>>>>>> to the appropriate security world's address space, maintaining
>>>>>> isolation
>>>>>> between secure and non-secure DMA operations.
>>>>> I don’t think that VFIO cares about secure regime, my guess is to
>>>>> keep the functions as this and don’t call them for secure
>>>>> invalidations.
>>>> So do we want to prevent VFIO devices from working in secure mode
>>>> along
>>>> with the SMMU?
>>> Yes, my impression was that VFIO only works with NS devices, for
>>> example
>>> I see vfio_iommu_map_notify() only deals with system memory:
>>>
>>> if (iotlb->target_as != &address_space_memory) {
>>> error_setg(&local_err,
>>> "Wrong target AS \"%s\", only system memory is
>>> allowed",
>> Indeed this would need to be changed. I am totally fine not supporting
>> VFIO nor vhost devices (which also use unmap notifiers) in secure more.
>> However in that case I think the series would need to properly check
>> that those devices are not used in secure regime.
>
>
> Thanks for the clarification.
>
>
> For this series, I’m fine not supporting VFIO/vhost in Secure regime.
> I’ll add a fail-fast check at smmuv3_inv_notifiers_iova to reject
> devices using IOMMU notifiers when the selected regime is non-NS. The
> NS path stays unchanged.
>
>
> /* invalidate an asid/vmid/iova range tuple in all mr's */
> static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
> dma_addr_t iova, uint8_t tg,
> uint64_t num_pages, int stage,
> SMMUSecSID sec_sid)
> {
> SMMUDevice *sdev;
> if (sec_sid != SMMU_SEC_SID_NS) { // fail-fast check
> return;
> }
> ......
> }
You can do that earlier on notifier registration I think
Eric
>
>
> Best regards,
>
> Tao
>
>
>>
>> Thanks
>>
>> Eric
>>>
>>> Otherwise, the callback needs to be enlighted by different address
>>> spaces, I am not sure how (and what uses cases?) will that be done,
>>> does
>>> QEMU emulate TZ in that case? (and present some devices as secure?)
>>>
>>> Thanks,
>>> Mostafa
>>>
>>>> Eric
>>>>> Thanks,
>>>>> Mostafa
>>>>>
>>>>>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>>>>>> ---
>>>>>> hw/arm/smmuv3.c | 18 +++++++++++-------
>>>>>> 1 file changed, 11 insertions(+), 7 deletions(-)
>>>>>>
>>>>>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>>>>>> index 4a4de719a7c..e33a7babd1c 100644
>>>>>> --- a/hw/arm/smmuv3.c
>>>>>> +++ b/hw/arm/smmuv3.c
>>>>>> @@ -1195,15 +1195,16 @@ epilogue:
>>>>>> * @tg: translation granule (if communicated through range
>>>>>> invalidation)
>>>>>> * @num_pages: number of @granule sized pages (if tg != 0),
>>>>>> otherwise 1
>>>>>> * @stage: Which stage(1 or 2) is used
>>>>>> + * @sec_sid: StreamID Security state
>>>>>> */
>>>>>> static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>>>>> IOMMUNotifier *n,
>>>>>> int asid, int vmid,
>>>>>> dma_addr_t iova, uint8_t tg,
>>>>>> - uint64_t num_pages, int stage)
>>>>>> + uint64_t num_pages, int stage,
>>>>>> + SMMUSecSID sec_sid)
>>>>>> {
>>>>>> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
>>>>>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>>>>>> SMMUEventInfo eventinfo = {.sec_sid = sec_sid,
>>>>>> .inval_ste_allowed = true};
>>>>>> SMMUTransCfg *cfg = smmuv3_get_config(sdev, &eventinfo,
>>>>>> sec_sid);
>>>>>> @@ -1251,7 +1252,8 @@ static void
>>>>>> smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>>>>> }
>>>>>> event.type = IOMMU_NOTIFIER_UNMAP;
>>>>>> - event.entry.target_as = &address_space_memory;
>>>>>> + event.entry.target_as = smmu_get_address_space(sdev->smmu,
>>>>>> sec_sid);
>>>>>> + g_assert(event.entry.target_as);
>>>>>> event.entry.iova = iova;
>>>>>> event.entry.addr_mask = num_pages * (1 << granule) - 1;
>>>>>> event.entry.perm = IOMMU_NONE;
>>>>>> @@ -1262,7 +1264,8 @@ static void
>>>>>> smmuv3_notify_iova(IOMMUMemoryRegion *mr,
>>>>>> /* invalidate an asid/vmid/iova range tuple in all mr's */
>>>>>> static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid,
>>>>>> int vmid,
>>>>>> dma_addr_t iova, uint8_t tg,
>>>>>> - uint64_t num_pages, int
>>>>>> stage)
>>>>>> + uint64_t num_pages, int
>>>>>> stage,
>>>>>> + SMMUSecSID sec_sid)
>>>>>> {
>>>>>> SMMUDevice *sdev;
>>>>>> @@ -1274,7 +1277,8 @@ static void
>>>>>> smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
>>>>>> iova, tg, num_pages,
>>>>>> stage);
>>>>>> IOMMU_NOTIFIER_FOREACH(n, mr) {
>>>>>> - smmuv3_notify_iova(mr, n, asid, vmid, iova, tg,
>>>>>> num_pages, stage);
>>>>>> + smmuv3_notify_iova(mr, n, asid, vmid, iova, tg,
>>>>>> + num_pages, stage, sec_sid);
>>>>>> }
>>>>>> }
>>>>>> }
>>>>>> @@ -1307,7 +1311,7 @@ static void smmuv3_range_inval(SMMUState
>>>>>> *s, Cmd *cmd, SMMUStage stage,
>>>>>> if (!tg) {
>>>>>> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr,
>>>>>> tg, 1, ttl, leaf, stage);
>>>>>> - smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1,
>>>>>> stage);
>>>>>> + smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1,
>>>>>> stage, sec_sid);
>>>>>> if (stage == SMMU_STAGE_1) {
>>>>>> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1,
>>>>>> ttl, sec_sid);
>>>>>> } else {
>>>>>> @@ -1331,7 +1335,7 @@ static void smmuv3_range_inval(SMMUState
>>>>>> *s, Cmd *cmd, SMMUStage stage,
>>>>>> trace_smmuv3_range_inval(sec_sid, vmid, asid, addr, tg,
>>>>>> num_pages, ttl, leaf, stage);
>>>>>> smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg,
>>>>>> - num_pages, stage);
>>>>>> + num_pages, stage, sec_sid);
>>>>>> if (stage == SMMU_STAGE_1) {
>>>>>> smmu_iotlb_inv_iova(s, asid, vmid, addr, tg,
>>>>>> num_pages, ttl, sec_sid);
>>>>>> --
>>>>>> 2.34.1
>>>>>>
>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 17/31] hw/arm/smmuv3: Pass sec_sid into cmdq consume path
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (15 preceding siblings ...)
2026-02-21 10:17 ` [RFC v4 16/31] hw/arm/smmuv3: Plumb SEC_SID through IOMMU notifier path Tao Tang
@ 2026-02-21 10:17 ` Tao Tang
2026-02-25 21:35 ` Pierrick Bouvier
2026-03-03 10:14 ` Eric Auger
2026-02-21 10:17 ` [RFC v4 18/31] hw/arm/smmuv3: Make evtq producer use SEC_SID Tao Tang
` (13 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:17 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Make smmuv3_cmdq_consume() security-state aware by passing sec_sid
from smmu_writel() call sites (CR0/GERRORN/CMDQ_PROD paths), instead
of hardcoding non-secure state. The related AddressSpace and MemTxAttrs
are also obtained based on sec_sid.
Also move CMD_SSEC legality checking to a single early check before
command dispatch: secure commands are rejected on non-secure queues
(including future Realm queue) with CERROR_ILL. This removes duplicated
per-command checks in CFGI handlers.
Finally, extend cmdq trace output with sec_sid so command processing
can be correlated with the correct security bank.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 50 ++++++++++++++++++++++-----------------------
hw/arm/trace-events | 2 +-
2 files changed, 26 insertions(+), 26 deletions(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index e33a7babd1c..b2559e80f24 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -111,14 +111,14 @@ static void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_gerrorn)
trace_smmuv3_write_gerrorn(toggled & pending, bank->gerrorn);
}
-static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd)
+static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd,
+ AddressSpace *as, MemTxAttrs attrs)
{
dma_addr_t addr = Q_CONS_ENTRY(q);
MemTxResult ret;
int i;
- ret = dma_memory_read(&address_space_memory, addr, cmd, sizeof(Cmd),
- MEMTXATTRS_UNSPECIFIED);
+ ret = dma_memory_read(as, addr, cmd, sizeof(Cmd), attrs);
if (ret != MEMTX_OK) {
return ret;
}
@@ -1346,14 +1346,17 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
}
}
-static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
+static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
{
SMMUState *bs = ARM_SMMU(s);
SMMUCmdError cmd_error = SMMU_CERROR_NONE;
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
SMMUQueue *q = &bank->cmdq;
SMMUCommandType type = 0;
+ MemTxAttrs attrs = smmu_get_txattrs(sec_sid);
+ AddressSpace *as = smmu_get_address_space(bs, sec_sid);
+ /* Secure AddressSpace must be available, assert if not. */
+ g_assert(as);
if (!smmuv3_cmdq_enabled(s, sec_sid)) {
return 0;
@@ -1369,18 +1372,30 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
uint32_t pending = bank->gerror ^ bank->gerrorn;
Cmd cmd;
- trace_smmuv3_cmdq_consume(Q_PROD(q), Q_CONS(q),
+ trace_smmuv3_cmdq_consume(sec_sid, Q_PROD(q), Q_CONS(q),
Q_PROD_WRAP(q), Q_CONS_WRAP(q));
if (FIELD_EX32(pending, GERROR, CMDQ_ERR)) {
break;
}
- if (queue_read(q, &cmd) != MEMTX_OK) {
+ if (queue_read(q, &cmd, as, attrs) != MEMTX_OK) {
cmd_error = SMMU_CERROR_ABT;
break;
}
+ /*
+ * Secure Command on Non-secure Command queue, including Realm Command
+ * queue, is not allowed. CERROR_ILL will be raised according to
+ * (IHI 0070G.b) 4.1.6 Common command fields, Page 168.
+ */
+ if (CMD_SSEC(&cmd)) {
+ if (sec_sid != SMMU_SEC_SID_S) {
+ cmd_error = SMMU_CERROR_ILL;
+ break;
+ }
+ }
+
type = CMD_TYPE(&cmd);
trace_smmuv3_cmdq_opcode(smmu_cmd_string(type));
@@ -1400,11 +1415,6 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
uint32_t sid = CMD_SID(&cmd);
SMMUDevice *sdev = smmu_find_sdev(bs, sid);
- if (CMD_SSEC(&cmd)) {
- cmd_error = SMMU_CERROR_ILL;
- break;
- }
-
if (!sdev) {
break;
}
@@ -1424,11 +1434,6 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
uint8_t range = CMD_STE_RANGE(&cmd);
SMMUSIDRange sid_range;
- if (CMD_SSEC(&cmd)) {
- cmd_error = SMMU_CERROR_ILL;
- break;
- }
-
mask = (1ULL << (range + 1)) - 1;
sid_range.start = sid & ~mask;
sid_range.end = sid_range.start + mask;
@@ -1447,11 +1452,6 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
uint32_t sid = CMD_SID(&cmd);
SMMUDevice *sdev = smmu_find_sdev(bs, sid);
- if (CMD_SSEC(&cmd)) {
- cmd_error = SMMU_CERROR_ILL;
- break;
- }
-
if (!sdev) {
break;
}
@@ -1666,7 +1666,7 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
bank->cr[0] = data;
bank->cr0ack = data & ~SMMU_CR0_RESERVED;
/* in case the command queue has been enabled */
- smmuv3_cmdq_consume(s, &local_err);
+ smmuv3_cmdq_consume(s, &local_err, reg_sec_sid);
break;
case A_CR1:
bank->cr[1] = data;
@@ -1683,7 +1683,7 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
* By acknowledging the CMDQ_ERR, SW may notify cmds can
* be processed again
*/
- smmuv3_cmdq_consume(s, &local_err);
+ smmuv3_cmdq_consume(s, &local_err, reg_sec_sid);
break;
case A_GERROR_IRQ_CFG0: /* 64b */
bank->gerror_irq_cfg0 = deposit64(bank->gerror_irq_cfg0, 0, 32, data);
@@ -1733,7 +1733,7 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
break;
case A_CMDQ_PROD:
bank->cmdq.prod = data;
- smmuv3_cmdq_consume(s, &local_err);
+ smmuv3_cmdq_consume(s, &local_err, reg_sec_sid);
break;
case A_CMDQ_CONS:
bank->cmdq.cons = data;
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index 4e360b3c0d3..ca8485c96af 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -35,7 +35,7 @@ smmuv3_trigger_irq(int irq) "irq=%d"
smmuv3_write_gerror(uint32_t toggled, uint32_t gerror) "toggled=0x%x, new GERROR=0x%x"
smmuv3_write_gerrorn(uint32_t acked, uint32_t gerrorn) "acked=0x%x, new GERRORN=0x%x"
smmuv3_unhandled_cmd(uint32_t type) "Unhandled command type=%d"
-smmuv3_cmdq_consume(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod=%d cons=%d prod.wrap=%d cons.wrap=%d"
+smmuv3_cmdq_consume(int sec_sid, uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "sec_sid=%d prod=%d cons=%d prod.wrap=%d cons.wrap=%d"
smmuv3_cmdq_opcode(const char *opcode) "<--- %s"
smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d "
smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error on %s command execution: %d"
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 17/31] hw/arm/smmuv3: Pass sec_sid into cmdq consume path
2026-02-21 10:17 ` [RFC v4 17/31] hw/arm/smmuv3: Pass sec_sid into cmdq consume path Tao Tang
@ 2026-02-25 21:35 ` Pierrick Bouvier
2026-03-03 10:14 ` Eric Auger
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:35 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:17 AM, Tao Tang wrote:
> Make smmuv3_cmdq_consume() security-state aware by passing sec_sid
> from smmu_writel() call sites (CR0/GERRORN/CMDQ_PROD paths), instead
> of hardcoding non-secure state. The related AddressSpace and MemTxAttrs
> are also obtained based on sec_sid.
>
> Also move CMD_SSEC legality checking to a single early check before
> command dispatch: secure commands are rejected on non-secure queues
> (including future Realm queue) with CERROR_ILL. This removes duplicated
> per-command checks in CFGI handlers.
>
Sounds great!
> Finally, extend cmdq trace output with sec_sid so command processing
> can be correlated with the correct security bank.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 50 ++++++++++++++++++++++-----------------------
> hw/arm/trace-events | 2 +-
> 2 files changed, 26 insertions(+), 26 deletions(-)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index e33a7babd1c..b2559e80f24 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -111,14 +111,14 @@ static void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_gerrorn)
> trace_smmuv3_write_gerrorn(toggled & pending, bank->gerrorn);
> }
>
> -static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd)
> +static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd,
> + AddressSpace *as, MemTxAttrs attrs)
> {
> dma_addr_t addr = Q_CONS_ENTRY(q);
> MemTxResult ret;
> int i;
>
> - ret = dma_memory_read(&address_space_memory, addr, cmd, sizeof(Cmd),
> - MEMTXATTRS_UNSPECIFIED);
> + ret = dma_memory_read(as, addr, cmd, sizeof(Cmd), attrs);
> if (ret != MEMTX_OK) {
> return ret;
> }
> @@ -1346,14 +1346,17 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
> }
> }
>
> -static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> +static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> {
> SMMUState *bs = ARM_SMMU(s);
> SMMUCmdError cmd_error = SMMU_CERROR_NONE;
> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> SMMUQueue *q = &bank->cmdq;
> SMMUCommandType type = 0;
> + MemTxAttrs attrs = smmu_get_txattrs(sec_sid);
> + AddressSpace *as = smmu_get_address_space(bs, sec_sid);
> + /* Secure AddressSpace must be available, assert if not. */
> + g_assert(as);
>
This will be automatically be handled if we check in smmu_base_realize
that secure smmu support should be available, as mentioned on one of the
previous patch.
> if (!smmuv3_cmdq_enabled(s, sec_sid)) {
> return 0;
> @@ -1369,18 +1372,30 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> uint32_t pending = bank->gerror ^ bank->gerrorn;
> Cmd cmd;
>
> - trace_smmuv3_cmdq_consume(Q_PROD(q), Q_CONS(q),
> + trace_smmuv3_cmdq_consume(sec_sid, Q_PROD(q), Q_CONS(q),
> Q_PROD_WRAP(q), Q_CONS_WRAP(q));
>
> if (FIELD_EX32(pending, GERROR, CMDQ_ERR)) {
> break;
> }
>
> - if (queue_read(q, &cmd) != MEMTX_OK) {
> + if (queue_read(q, &cmd, as, attrs) != MEMTX_OK) {
> cmd_error = SMMU_CERROR_ABT;
> break;
> }
>
> + /*
> + * Secure Command on Non-secure Command queue, including Realm Command
> + * queue, is not allowed. CERROR_ILL will be raised according to
> + * (IHI 0070G.b) 4.1.6 Common command fields, Page 168.
> + */
> + if (CMD_SSEC(&cmd)) {
> + if (sec_sid != SMMU_SEC_SID_S) {
> + cmd_error = SMMU_CERROR_ILL;
> + break;
> + }
> + }
> +
> type = CMD_TYPE(&cmd);
>
> trace_smmuv3_cmdq_opcode(smmu_cmd_string(type));
> @@ -1400,11 +1415,6 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> uint32_t sid = CMD_SID(&cmd);
> SMMUDevice *sdev = smmu_find_sdev(bs, sid);
>
> - if (CMD_SSEC(&cmd)) {
> - cmd_error = SMMU_CERROR_ILL;
> - break;
> - }
> -
> if (!sdev) {
> break;
> }
> @@ -1424,11 +1434,6 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> uint8_t range = CMD_STE_RANGE(&cmd);
> SMMUSIDRange sid_range;
>
> - if (CMD_SSEC(&cmd)) {
> - cmd_error = SMMU_CERROR_ILL;
> - break;
> - }
> -
> mask = (1ULL << (range + 1)) - 1;
> sid_range.start = sid & ~mask;
> sid_range.end = sid_range.start + mask;
> @@ -1447,11 +1452,6 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> uint32_t sid = CMD_SID(&cmd);
> SMMUDevice *sdev = smmu_find_sdev(bs, sid);
>
> - if (CMD_SSEC(&cmd)) {
> - cmd_error = SMMU_CERROR_ILL;
> - break;
> - }
> -
> if (!sdev) {
> break;
> }
> @@ -1666,7 +1666,7 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
> bank->cr[0] = data;
> bank->cr0ack = data & ~SMMU_CR0_RESERVED;
> /* in case the command queue has been enabled */
> - smmuv3_cmdq_consume(s, &local_err);
> + smmuv3_cmdq_consume(s, &local_err, reg_sec_sid);
> break;
> case A_CR1:
> bank->cr[1] = data;
> @@ -1683,7 +1683,7 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
> * By acknowledging the CMDQ_ERR, SW may notify cmds can
> * be processed again
> */
> - smmuv3_cmdq_consume(s, &local_err);
> + smmuv3_cmdq_consume(s, &local_err, reg_sec_sid);
> break;
> case A_GERROR_IRQ_CFG0: /* 64b */
> bank->gerror_irq_cfg0 = deposit64(bank->gerror_irq_cfg0, 0, 32, data);
> @@ -1733,7 +1733,7 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
> break;
> case A_CMDQ_PROD:
> bank->cmdq.prod = data;
> - smmuv3_cmdq_consume(s, &local_err);
> + smmuv3_cmdq_consume(s, &local_err, reg_sec_sid);
> break;
> case A_CMDQ_CONS:
> bank->cmdq.cons = data;
> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> index 4e360b3c0d3..ca8485c96af 100644
> --- a/hw/arm/trace-events
> +++ b/hw/arm/trace-events
> @@ -35,7 +35,7 @@ smmuv3_trigger_irq(int irq) "irq=%d"
> smmuv3_write_gerror(uint32_t toggled, uint32_t gerror) "toggled=0x%x, new GERROR=0x%x"
> smmuv3_write_gerrorn(uint32_t acked, uint32_t gerrorn) "acked=0x%x, new GERRORN=0x%x"
> smmuv3_unhandled_cmd(uint32_t type) "Unhandled command type=%d"
> -smmuv3_cmdq_consume(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod=%d cons=%d prod.wrap=%d cons.wrap=%d"
> +smmuv3_cmdq_consume(int sec_sid, uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "sec_sid=%d prod=%d cons=%d prod.wrap=%d cons.wrap=%d"
> smmuv3_cmdq_opcode(const char *opcode) "<--- %s"
> smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d "
> smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error on %s command execution: %d"
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 17/31] hw/arm/smmuv3: Pass sec_sid into cmdq consume path
2026-02-21 10:17 ` [RFC v4 17/31] hw/arm/smmuv3: Pass sec_sid into cmdq consume path Tao Tang
2026-02-25 21:35 ` Pierrick Bouvier
@ 2026-03-03 10:14 ` Eric Auger
2026-03-05 14:42 ` Tao Tang
1 sibling, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-03 10:14 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 2/21/26 11:17 AM, Tao Tang wrote:
> Make smmuv3_cmdq_consume() security-state aware by passing sec_sid
> from smmu_writel() call sites (CR0/GERRORN/CMDQ_PROD paths), instead
> of hardcoding non-secure state. The related AddressSpace and MemTxAttrs
> are also obtained based on sec_sid.
>
> Also move CMD_SSEC legality checking to a single early check before
> command dispatch: secure commands are rejected on non-secure queues
> (including future Realm queue) with CERROR_ILL. This removes duplicated
> per-command checks in CFGI handlers.
>
> Finally, extend cmdq trace output with sec_sid so command processing
> can be correlated with the correct security bank.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 50 ++++++++++++++++++++++-----------------------
> hw/arm/trace-events | 2 +-
> 2 files changed, 26 insertions(+), 26 deletions(-)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index e33a7babd1c..b2559e80f24 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -111,14 +111,14 @@ static void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_gerrorn)
> trace_smmuv3_write_gerrorn(toggled & pending, bank->gerrorn);
> }
>
> -static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd)
> +static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd,
> + AddressSpace *as, MemTxAttrs attrs)
> {
> dma_addr_t addr = Q_CONS_ENTRY(q);
> MemTxResult ret;
> int i;
>
> - ret = dma_memory_read(&address_space_memory, addr, cmd, sizeof(Cmd),
> - MEMTXATTRS_UNSPECIFIED);
> + ret = dma_memory_read(as, addr, cmd, sizeof(Cmd), attrs);
> if (ret != MEMTX_OK) {
> return ret;
> }
> @@ -1346,14 +1346,17 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
> }
> }
>
> -static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> +static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> {
> SMMUState *bs = ARM_SMMU(s);
> SMMUCmdError cmd_error = SMMU_CERROR_NONE;
> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> SMMUQueue *q = &bank->cmdq;
> SMMUCommandType type = 0;
> + MemTxAttrs attrs = smmu_get_txattrs(sec_sid);
> + AddressSpace *as = smmu_get_address_space(bs, sec_sid);
> + /* Secure AddressSpace must be available, assert if not. */
> + g_assert(as);
pls remove that check
>
> if (!smmuv3_cmdq_enabled(s, sec_sid)) {
> return 0;
> @@ -1369,18 +1372,30 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> uint32_t pending = bank->gerror ^ bank->gerrorn;
> Cmd cmd;
>
> - trace_smmuv3_cmdq_consume(Q_PROD(q), Q_CONS(q),
> + trace_smmuv3_cmdq_consume(sec_sid, Q_PROD(q), Q_CONS(q),
> Q_PROD_WRAP(q), Q_CONS_WRAP(q));
>
> if (FIELD_EX32(pending, GERROR, CMDQ_ERR)) {
> break;
> }
>
> - if (queue_read(q, &cmd) != MEMTX_OK) {
> + if (queue_read(q, &cmd, as, attrs) != MEMTX_OK) {
> cmd_error = SMMU_CERROR_ABT;
> break;
> }
>
> + /*
> + * Secure Command on Non-secure Command queue, including Realm Command
> + * queue, is not allowed. CERROR_ILL will be raised according to
> + * (IHI 0070G.b) 4.1.6 Common command fields, Page 168.
> + */
> + if (CMD_SSEC(&cmd)) {
> + if (sec_sid != SMMU_SEC_SID_S) {
nit combine both checks
> + cmd_error = SMMU_CERROR_ILL;
> + break;
> + }
> + }
> +
> type = CMD_TYPE(&cmd);
>
> trace_smmuv3_cmdq_opcode(smmu_cmd_string(type));
> @@ -1400,11 +1415,6 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> uint32_t sid = CMD_SID(&cmd);
> SMMUDevice *sdev = smmu_find_sdev(bs, sid);
>
> - if (CMD_SSEC(&cmd)) {
> - cmd_error = SMMU_CERROR_ILL;
> - break;
> - }
> -
> if (!sdev) {
> break;
> }
> @@ -1424,11 +1434,6 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> uint8_t range = CMD_STE_RANGE(&cmd);
> SMMUSIDRange sid_range;
>
> - if (CMD_SSEC(&cmd)) {
> - cmd_error = SMMU_CERROR_ILL;
> - break;
> - }
> -
> mask = (1ULL << (range + 1)) - 1;
> sid_range.start = sid & ~mask;
> sid_range.end = sid_range.start + mask;
> @@ -1447,11 +1452,6 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
> uint32_t sid = CMD_SID(&cmd);
> SMMUDevice *sdev = smmu_find_sdev(bs, sid);
>
> - if (CMD_SSEC(&cmd)) {
> - cmd_error = SMMU_CERROR_ILL;
> - break;
> - }
> -
> if (!sdev) {
> break;
> }
> @@ -1666,7 +1666,7 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
> bank->cr[0] = data;
> bank->cr0ack = data & ~SMMU_CR0_RESERVED;
> /* in case the command queue has been enabled */
> - smmuv3_cmdq_consume(s, &local_err);
> + smmuv3_cmdq_consume(s, &local_err, reg_sec_sid);
> break;
> case A_CR1:
> bank->cr[1] = data;
> @@ -1683,7 +1683,7 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
> * By acknowledging the CMDQ_ERR, SW may notify cmds can
> * be processed again
> */
> - smmuv3_cmdq_consume(s, &local_err);
> + smmuv3_cmdq_consume(s, &local_err, reg_sec_sid);
> break;
> case A_GERROR_IRQ_CFG0: /* 64b */
> bank->gerror_irq_cfg0 = deposit64(bank->gerror_irq_cfg0, 0, 32, data);
> @@ -1733,7 +1733,7 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
> break;
> case A_CMDQ_PROD:
> bank->cmdq.prod = data;
> - smmuv3_cmdq_consume(s, &local_err);
> + smmuv3_cmdq_consume(s, &local_err, reg_sec_sid);
> break;
> case A_CMDQ_CONS:
> bank->cmdq.cons = data;
> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> index 4e360b3c0d3..ca8485c96af 100644
> --- a/hw/arm/trace-events
> +++ b/hw/arm/trace-events
> @@ -35,7 +35,7 @@ smmuv3_trigger_irq(int irq) "irq=%d"
> smmuv3_write_gerror(uint32_t toggled, uint32_t gerror) "toggled=0x%x, new GERROR=0x%x"
> smmuv3_write_gerrorn(uint32_t acked, uint32_t gerrorn) "acked=0x%x, new GERRORN=0x%x"
> smmuv3_unhandled_cmd(uint32_t type) "Unhandled command type=%d"
> -smmuv3_cmdq_consume(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod=%d cons=%d prod.wrap=%d cons.wrap=%d"
> +smmuv3_cmdq_consume(int sec_sid, uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "sec_sid=%d prod=%d cons=%d prod.wrap=%d cons.wrap=%d"
> smmuv3_cmdq_opcode(const char *opcode) "<--- %s"
> smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d "
> smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error on %s command execution: %d"
Besides looks good to me
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 17/31] hw/arm/smmuv3: Pass sec_sid into cmdq consume path
2026-03-03 10:14 ` Eric Auger
@ 2026-03-05 14:42 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-05 14:42 UTC (permalink / raw)
To: eric.auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi Eric,
On 2026/3/3 18:14, Eric Auger wrote:
>
> On 2/21/26 11:17 AM, Tao Tang wrote:
>> Make smmuv3_cmdq_consume() security-state aware by passing sec_sid
>> from smmu_writel() call sites (CR0/GERRORN/CMDQ_PROD paths), instead
>> of hardcoding non-secure state. The related AddressSpace and MemTxAttrs
>> are also obtained based on sec_sid.
>>
>> Also move CMD_SSEC legality checking to a single early check before
>> command dispatch: secure commands are rejected on non-secure queues
>> (including future Realm queue) with CERROR_ILL. This removes duplicated
>> per-command checks in CFGI handlers.
>>
>> Finally, extend cmdq trace output with sec_sid so command processing
>> can be correlated with the correct security bank.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmuv3.c | 50 ++++++++++++++++++++++-----------------------
>> hw/arm/trace-events | 2 +-
>> 2 files changed, 26 insertions(+), 26 deletions(-)
>>
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index e33a7babd1c..b2559e80f24 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -111,14 +111,14 @@ static void smmuv3_write_gerrorn(SMMUv3State *s, uint32_t new_gerrorn)
>> trace_smmuv3_write_gerrorn(toggled & pending, bank->gerrorn);
>> }
>>
>> -static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd)
>> +static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd,
>> + AddressSpace *as, MemTxAttrs attrs)
>> {
>> dma_addr_t addr = Q_CONS_ENTRY(q);
>> MemTxResult ret;
>> int i;
>>
>> - ret = dma_memory_read(&address_space_memory, addr, cmd, sizeof(Cmd),
>> - MEMTXATTRS_UNSPECIFIED);
>> + ret = dma_memory_read(as, addr, cmd, sizeof(Cmd), attrs);
>> if (ret != MEMTX_OK) {
>> return ret;
>> }
>> @@ -1346,14 +1346,17 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
>> }
>> }
>>
>> -static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
>> +static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
>> {
>> SMMUState *bs = ARM_SMMU(s);
>> SMMUCmdError cmd_error = SMMU_CERROR_NONE;
>> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
>> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
>> SMMUQueue *q = &bank->cmdq;
>> SMMUCommandType type = 0;
>> + MemTxAttrs attrs = smmu_get_txattrs(sec_sid);
>> + AddressSpace *as = smmu_get_address_space(bs, sec_sid);
>> + /* Secure AddressSpace must be available, assert if not. */
>> + g_assert(as);
> pls remove that check
I'll remove all the unnecessary assertions and check it in lower level
instead.
>>
>> if (!smmuv3_cmdq_enabled(s, sec_sid)) {
>> return 0;
>> @@ -1369,18 +1372,30 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp)
>> uint32_t pending = bank->gerror ^ bank->gerrorn;
>> Cmd cmd;
>>
>> - trace_smmuv3_cmdq_consume(Q_PROD(q), Q_CONS(q),
>> + trace_smmuv3_cmdq_consume(sec_sid, Q_PROD(q), Q_CONS(q),
>> Q_PROD_WRAP(q), Q_CONS_WRAP(q));
>>
>> if (FIELD_EX32(pending, GERROR, CMDQ_ERR)) {
>> break;
>> }
>>
>> - if (queue_read(q, &cmd) != MEMTX_OK) {
>> + if (queue_read(q, &cmd, as, attrs) != MEMTX_OK) {
>> cmd_error = SMMU_CERROR_ABT;
>> break;
>> }
>>
>> + /*
>> + * Secure Command on Non-secure Command queue, including Realm Command
>> + * queue, is not allowed. CERROR_ILL will be raised according to
>> + * (IHI 0070G.b) 4.1.6 Common command fields, Page 168.
>> + */
>> + if (CMD_SSEC(&cmd)) {
>> + if (sec_sid != SMMU_SEC_SID_S) {
> nit combine both checks
OK.
>> + cmd_error = SMMU_CERROR_ILL;
>> + break;
>> + }
>> + }
>> +
>> type = CMD_TYPE(&cmd);
>>
>> trace_smmuv3_cmdq_opcode(smmu_cmd_string(type));
>> ------------------------------<snip>------------------------------
>>
>>
>>
>> ------------------------------<snip>------------------------------
>> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
>> index 4e360b3c0d3..ca8485c96af 100644
>> --- a/hw/arm/trace-events
>> +++ b/hw/arm/trace-events
>> @@ -35,7 +35,7 @@ smmuv3_trigger_irq(int irq) "irq=%d"
>> smmuv3_write_gerror(uint32_t toggled, uint32_t gerror) "toggled=0x%x, new GERROR=0x%x"
>> smmuv3_write_gerrorn(uint32_t acked, uint32_t gerrorn) "acked=0x%x, new GERRORN=0x%x"
>> smmuv3_unhandled_cmd(uint32_t type) "Unhandled command type=%d"
>> -smmuv3_cmdq_consume(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod=%d cons=%d prod.wrap=%d cons.wrap=%d"
>> +smmuv3_cmdq_consume(int sec_sid, uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "sec_sid=%d prod=%d cons=%d prod.wrap=%d cons.wrap=%d"
>> smmuv3_cmdq_opcode(const char *opcode) "<--- %s"
>> smmuv3_cmdq_consume_out(uint32_t prod, uint32_t cons, uint8_t prod_wrap, uint8_t cons_wrap) "prod:%d, cons:%d, prod_wrap:%d, cons_wrap:%d "
>> smmuv3_cmdq_consume_error(const char *cmd_name, uint8_t cmd_error) "Error on %s command execution: %d"
> Besides looks good to me
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>
> Eric
Thanks,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 18/31] hw/arm/smmuv3: Make evtq producer use SEC_SID
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (16 preceding siblings ...)
2026-02-21 10:17 ` [RFC v4 17/31] hw/arm/smmuv3: Pass sec_sid into cmdq consume path Tao Tang
@ 2026-02-21 10:17 ` Tao Tang
2026-02-25 21:40 ` Pierrick Bouvier
2026-03-03 10:16 ` Eric Auger
2026-02-21 10:17 ` [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported Tao Tang
` (12 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:17 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
The event queue producer path wrote entries through address_space_memory
with MEMTXATTRS_UNSPECIFIED, so produced entries did not use the
sec_sid-selected DMA context.
Pass AddressSpace and MemTxAttrs to queue_write() from sec_sid, and
assert that the selected AddressSpace exists before producing entries.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index b2559e80f24..fa09099a09a 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -128,7 +128,8 @@ static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd,
return ret;
}
-static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
+static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in,
+ AddressSpace *as, MemTxAttrs attrs)
{
dma_addr_t addr = Q_PROD_ENTRY(q);
MemTxResult ret;
@@ -138,8 +139,7 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
for (i = 0; i < ARRAY_SIZE(evt.word); i++) {
cpu_to_le32s(&evt.word[i]);
}
- ret = dma_memory_write(&address_space_memory, addr, &evt, sizeof(Evt),
- MEMTXATTRS_UNSPECIFIED);
+ ret = dma_memory_write(as, addr, &evt, sizeof(Evt), attrs);
if (ret != MEMTX_OK) {
return ret;
}
@@ -154,6 +154,11 @@ static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
SMMUQueue *q = &bank->eventq;
MemTxResult r;
+ SMMUState *bs = ARM_SMMU(s);
+ MemTxAttrs txattrs = smmu_get_txattrs(sec_sid);
+ AddressSpace *as = smmu_get_address_space(bs, sec_sid);
+ /* Secure AddressSpace must be available, assert if not. */
+ g_assert(as);
if (!smmuv3_eventq_enabled(s, sec_sid)) {
return MEMTX_ERROR;
@@ -163,7 +168,7 @@ static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
return MEMTX_ERROR;
}
- r = queue_write(q, evt);
+ r = queue_write(q, evt, as, txattrs);
if (r != MEMTX_OK) {
return r;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 18/31] hw/arm/smmuv3: Make evtq producer use SEC_SID
2026-02-21 10:17 ` [RFC v4 18/31] hw/arm/smmuv3: Make evtq producer use SEC_SID Tao Tang
@ 2026-02-25 21:40 ` Pierrick Bouvier
2026-03-03 10:16 ` Eric Auger
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:40 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:17 AM, Tao Tang wrote:
> The event queue producer path wrote entries through address_space_memory
> with MEMTXATTRS_UNSPECIFIED, so produced entries did not use the
> sec_sid-selected DMA context.
>
> Pass AddressSpace and MemTxAttrs to queue_write() from sec_sid, and
> assert that the selected AddressSpace exists before producing entries.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 13 +++++++++----
> 1 file changed, 9 insertions(+), 4 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 18/31] hw/arm/smmuv3: Make evtq producer use SEC_SID
2026-02-21 10:17 ` [RFC v4 18/31] hw/arm/smmuv3: Make evtq producer use SEC_SID Tao Tang
2026-02-25 21:40 ` Pierrick Bouvier
@ 2026-03-03 10:16 ` Eric Auger
1 sibling, 0 replies; 136+ messages in thread
From: Eric Auger @ 2026-03-03 10:16 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 2/21/26 11:17 AM, Tao Tang wrote:
> The event queue producer path wrote entries through address_space_memory
> with MEMTXATTRS_UNSPECIFIED, so produced entries did not use the
> sec_sid-selected DMA context.
>
> Pass AddressSpace and MemTxAttrs to queue_write() from sec_sid, and
> assert that the selected AddressSpace exists before producing entries.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 13 +++++++++----
> 1 file changed, 9 insertions(+), 4 deletions(-)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index b2559e80f24..fa09099a09a 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -128,7 +128,8 @@ static inline MemTxResult queue_read(SMMUQueue *q, Cmd *cmd,
> return ret;
> }
>
> -static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
> +static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in,
> + AddressSpace *as, MemTxAttrs attrs)
> {
> dma_addr_t addr = Q_PROD_ENTRY(q);
> MemTxResult ret;
> @@ -138,8 +139,7 @@ static MemTxResult queue_write(SMMUQueue *q, Evt *evt_in)
> for (i = 0; i < ARRAY_SIZE(evt.word); i++) {
> cpu_to_le32s(&evt.word[i]);
> }
> - ret = dma_memory_write(&address_space_memory, addr, &evt, sizeof(Evt),
> - MEMTXATTRS_UNSPECIFIED);
> + ret = dma_memory_write(as, addr, &evt, sizeof(Evt), attrs);
> if (ret != MEMTX_OK) {
> return ret;
> }
> @@ -154,6 +154,11 @@ static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> SMMUQueue *q = &bank->eventq;
> MemTxResult r;
> + SMMUState *bs = ARM_SMMU(s);
> + MemTxAttrs txattrs = smmu_get_txattrs(sec_sid);
> + AddressSpace *as = smmu_get_address_space(bs, sec_sid);
> + /* Secure AddressSpace must be available, assert if not. */
> + g_assert(as);
same, would get rid of that check and move it at lower level.
>
> if (!smmuv3_eventq_enabled(s, sec_sid)) {
> return MEMTX_ERROR;
> @@ -163,7 +168,7 @@ static MemTxResult smmuv3_write_eventq(SMMUv3State *s, SMMUSecSID sec_sid,
> return MEMTX_ERROR;
> }
>
> - r = queue_write(q, evt);
> + r = queue_write(q, evt, as, txattrs);
> if (r != MEMTX_OK) {
> return r;
> }
Besides,
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (17 preceding siblings ...)
2026-02-21 10:17 ` [RFC v4 18/31] hw/arm/smmuv3: Make evtq producer use SEC_SID Tao Tang
@ 2026-02-21 10:17 ` Tao Tang
2026-02-25 21:40 ` Pierrick Bouvier
` (2 more replies)
2026-02-21 10:17 ` [RFC v4 20/31] hw/arm/smmu: Make CMDQ invalidation security-state aware Tao Tang
` (11 subsequent siblings)
30 siblings, 3 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:17 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Add a STAGE1_SUPPORTED check in the CMD_CFGI_CD and CMD_CFGI_CD_ALL path
and return CERROR_ILL when stage-1 translation is not implemented,
matching the architecture requirement (IHI 0070G.b, page 176).
Fixes: 32cfd7f39e08 ("hw/arm/smmuv3: Cache/invalidate config data")
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index fa09099a09a..d4c58c0c724 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1461,6 +1461,15 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
break;
}
+ /*
+ * This command raises CERROR_ILL when stage 1 is not implemented
+ * according to (IHI 0070G.b) Page 176.
+ */
+ if (!STAGE1_SUPPORTED(s)) {
+ cmd_error = SMMU_CERROR_ILL;
+ break;
+ }
+
trace_smmuv3_cmdq_cfgi_cd(sid);
smmuv3_flush_config(sdev);
if (!smmuv3_accel_issue_inv_cmd(s, &cmd, sdev, errp)) {
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported
2026-02-21 10:17 ` [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported Tao Tang
@ 2026-02-25 21:40 ` Pierrick Bouvier
2026-02-27 14:49 ` Mostafa Saleh
2026-03-02 17:55 ` Eric Auger
2 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:40 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:17 AM, Tao Tang wrote:
> Add a STAGE1_SUPPORTED check in the CMD_CFGI_CD and CMD_CFGI_CD_ALL path
> and return CERROR_ILL when stage-1 translation is not implemented,
> matching the architecture requirement (IHI 0070G.b, page 176).
>
> Fixes: 32cfd7f39e08 ("hw/arm/smmuv3: Cache/invalidate config data")
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported
2026-02-21 10:17 ` [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported Tao Tang
2026-02-25 21:40 ` Pierrick Bouvier
@ 2026-02-27 14:49 ` Mostafa Saleh
2026-03-01 12:33 ` Tao Tang
2026-03-02 17:55 ` Eric Auger
2 siblings, 1 reply; 136+ messages in thread
From: Mostafa Saleh @ 2026-02-27 14:49 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sat, Feb 21, 2026 at 06:17:33PM +0800, Tao Tang wrote:
> Add a STAGE1_SUPPORTED check in the CMD_CFGI_CD and CMD_CFGI_CD_ALL path
> and return CERROR_ILL when stage-1 translation is not implemented,
> matching the architecture requirement (IHI 0070G.b, page 176).
>
> Fixes: 32cfd7f39e08 ("hw/arm/smmuv3: Cache/invalidate config data")
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
This is a separate fix, it can be sent standalone to make this series
smaller, similarly the first patch.
Also the "Fixes" comment is not accurate, that was probably broken from
the stage-2 implementation which was added later.
Reviewed-by: Mostafa Saleh <smostafa@google.com>
Thanks,
Mostafa
> ---
> hw/arm/smmuv3.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index fa09099a09a..d4c58c0c724 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1461,6 +1461,15 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> break;
> }
>
> + /*
> + * This command raises CERROR_ILL when stage 1 is not implemented
> + * according to (IHI 0070G.b) Page 176.
> + */
> + if (!STAGE1_SUPPORTED(s)) {
> + cmd_error = SMMU_CERROR_ILL;
> + break;
> + }
> +
> trace_smmuv3_cmdq_cfgi_cd(sid);
> smmuv3_flush_config(sdev);
> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, sdev, errp)) {
> --
> 2.34.1
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported
2026-02-27 14:49 ` Mostafa Saleh
@ 2026-03-01 12:33 ` Tao Tang
2026-03-02 10:10 ` Mostafa Saleh
` (2 more replies)
0 siblings, 3 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-01 12:33 UTC (permalink / raw)
To: Mostafa Saleh
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
[-- Attachment #1: Type: text/plain, Size: 1084 bytes --]
Hi Mostafa,
On 2026/2/27 PM10:49, Mostafa Saleh wrote:
> On Sat, Feb 21, 2026 at 06:17:33PM +0800, Tao Tang wrote:
>> Add a STAGE1_SUPPORTED check in the CMD_CFGI_CD and CMD_CFGI_CD_ALL path
>> and return CERROR_ILL when stage-1 translation is not implemented,
>> matching the architecture requirement (IHI 0070G.b, page 176).
>>
>> Fixes: 32cfd7f39e08 ("hw/arm/smmuv3: Cache/invalidate config data")
>> Signed-off-by: Tao Tang<tangtao1634@phytium.com.cn>
> This is a separate fix, it can be sent standalone to make this series
> smaller, similarly the first patch.
For #1, #2 and #19 commit (this one), since I’m not fully sure about the
expected process here, should I resend these already Reviewed-by fixes
as standalone patch respectively right now, and try to get them merged
first?
> Also the "Fixes" comment is not accurate, that was probably broken from
> the stage-2 implementation which was added later.
I'll remove "Fixes" when resending this commit.
> Reviewed-by: Mostafa Saleh<smostafa@google.com>
>
> Thanks,
> Mostafa
Thanks for your review.
Tao
[-- Attachment #2: Type: text/html, Size: 2220 bytes --]
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported
2026-03-01 12:33 ` Tao Tang
@ 2026-03-02 10:10 ` Mostafa Saleh
2026-03-02 17:47 ` Pierrick Bouvier
2026-03-02 17:51 ` Eric Auger
2 siblings, 0 replies; 136+ messages in thread
From: Mostafa Saleh @ 2026-03-02 10:10 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sun, Mar 01, 2026 at 08:33:15PM +0800, Tao Tang wrote:
> Hi Mostafa,
>
> On 2026/2/27 PM10:49, Mostafa Saleh wrote:
> > On Sat, Feb 21, 2026 at 06:17:33PM +0800, Tao Tang wrote:
> > > Add a STAGE1_SUPPORTED check in the CMD_CFGI_CD and CMD_CFGI_CD_ALL path
> > > and return CERROR_ILL when stage-1 translation is not implemented,
> > > matching the architecture requirement (IHI 0070G.b, page 176).
> > >
> > > Fixes: 32cfd7f39e08 ("hw/arm/smmuv3: Cache/invalidate config data")
> > > Signed-off-by: Tao Tang<tangtao1634@phytium.com.cn>
> > This is a separate fix, it can be sent standalone to make this series
> > smaller, similarly the first patch.
>
>
> For #1, #2 and #19 commit (this one), since I’m not fully sure about the
> expected process here, should I resend these already Reviewed-by fixes as
> standalone patch respectively right now, and try to get them merged first?
>
Yes, that's my own opinion, that would make this series smaller and
slightly easier to review, but it's up to Eric.
Thanks,
Mostafa
>
> > Also the "Fixes" comment is not accurate, that was probably broken from
> > the stage-2 implementation which was added later.
>
>
> I'll remove "Fixes" when resending this commit.
>
>
> > Reviewed-by: Mostafa Saleh<smostafa@google.com>
> >
> > Thanks,
> > Mostafa
>
>
> Thanks for your review.
>
> Tao
>
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported
2026-03-01 12:33 ` Tao Tang
2026-03-02 10:10 ` Mostafa Saleh
@ 2026-03-02 17:47 ` Pierrick Bouvier
2026-03-02 17:53 ` Eric Auger
2026-03-02 17:51 ` Eric Auger
2 siblings, 1 reply; 136+ messages in thread
From: Pierrick Bouvier @ 2026-03-02 17:47 UTC (permalink / raw)
To: Tao Tang, Mostafa Saleh
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Chao Liu
On 3/1/26 4:33 AM, Tao Tang wrote:
> Hi Mostafa,
>
> On 2026/2/27 PM10:49, Mostafa Saleh wrote:
>> On Sat, Feb 21, 2026 at 06:17:33PM +0800, Tao Tang wrote:
>>> Add a STAGE1_SUPPORTED check in the CMD_CFGI_CD and CMD_CFGI_CD_ALL path
>>> and return CERROR_ILL when stage-1 translation is not implemented,
>>> matching the architecture requirement (IHI 0070G.b, page 176).
>>>
>>> Fixes: 32cfd7f39e08 ("hw/arm/smmuv3: Cache/invalidate config data")
>>> Signed-off-by: Tao Tang<tangtao1634@phytium.com.cn>
>> This is a separate fix, it can be sent standalone to make this series
>> smaller, similarly the first patch.
>
>
> For #1, #2 and #19 commit (this one), since I’m not fully sure about the
> expected process here, should I resend these already Reviewed-by fixes
> as standalone patch respectively right now, and try to get them merged
> first?
>
If a set of patches is fully ready, you can always put them first in
next version, and ask the maintainer to pull this one.
If your current series needs them to build, I usually prefer to keep it
all together, instead of having two different series, and using a
Based-on tag. But it's a personal preference, some people prefer to see
several series.
Regards,
Pierrick
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported
2026-03-02 17:47 ` Pierrick Bouvier
@ 2026-03-02 17:53 ` Eric Auger
2026-03-04 13:39 ` Tao Tang
0 siblings, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-02 17:53 UTC (permalink / raw)
To: Pierrick Bouvier, Tao Tang, Mostafa Saleh
Cc: Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum, qemu-devel,
qemu-arm, Chen Baozi, Philippe Mathieu-Daudé, Chao Liu
On 3/2/26 6:47 PM, Pierrick Bouvier wrote:
> On 3/1/26 4:33 AM, Tao Tang wrote:
>> Hi Mostafa,
>>
>> On 2026/2/27 PM10:49, Mostafa Saleh wrote:
>>> On Sat, Feb 21, 2026 at 06:17:33PM +0800, Tao Tang wrote:
>>>> Add a STAGE1_SUPPORTED check in the CMD_CFGI_CD and CMD_CFGI_CD_ALL
>>>> path
>>>> and return CERROR_ILL when stage-1 translation is not implemented,
>>>> matching the architecture requirement (IHI 0070G.b, page 176).
>>>>
>>>> Fixes: 32cfd7f39e08 ("hw/arm/smmuv3: Cache/invalidate config data")
>>>> Signed-off-by: Tao Tang<tangtao1634@phytium.com.cn>
>>> This is a separate fix, it can be sent standalone to make this series
>>> smaller, similarly the first patch.
>>
>>
>> For #1, #2 and #19 commit (this one), since I’m not fully sure about
>> the expected process here, should I resend these already Reviewed-by
>> fixes as standalone patch respectively right now, and try to get
>> them merged first?
>>
>
> If a set of patches is fully ready, you can always put them first in
> next version, and ask the maintainer to pull this one.
> If your current series needs them to build, I usually prefer to keep
> it all together, instead of having two different series, and using a
> Based-on tag. But it's a personal preference, some people prefer to
> see several series.
Either, either send them in a separate series or put them at the
beginning. We are approaching the soft freeze so maybe a separate series
would be better.
Eric
>
> Regards,
> Pierrick
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported
2026-03-02 17:53 ` Eric Auger
@ 2026-03-04 13:39 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-04 13:39 UTC (permalink / raw)
To: eric.auger, Pierrick Bouvier, Mostafa Saleh
Cc: Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum, qemu-devel,
qemu-arm, Chen Baozi, Philippe Mathieu-Daudé, Chao Liu
Hi all,
On 2026/3/3 01:53, Eric Auger wrote:
>
> On 3/2/26 6:47 PM, Pierrick Bouvier wrote:
>> On 3/1/26 4:33 AM, Tao Tang wrote:
>>> Hi Mostafa,
>>>
>>> On 2026/2/27 PM10:49, Mostafa Saleh wrote:
>>>> On Sat, Feb 21, 2026 at 06:17:33PM +0800, Tao Tang wrote:
>>>>> Add a STAGE1_SUPPORTED check in the CMD_CFGI_CD and CMD_CFGI_CD_ALL
>>>>> path
>>>>> and return CERROR_ILL when stage-1 translation is not implemented,
>>>>> matching the architecture requirement (IHI 0070G.b, page 176).
>>>>>
>>>>> Fixes: 32cfd7f39e08 ("hw/arm/smmuv3: Cache/invalidate config data")
>>>>> Signed-off-by: Tao Tang<tangtao1634@phytium.com.cn>
>>>> This is a separate fix, it can be sent standalone to make this series
>>>> smaller, similarly the first patch.
>>>
>>> For #1, #2 and #19 commit (this one), since I’m not fully sure about
>>> the expected process here, should I resend these already Reviewed-by
>>> fixes as standalone patch respectively right now, and try to get
>>> them merged first?
>>>
>> If a set of patches is fully ready, you can always put them first in
>> next version, and ask the maintainer to pull this one.
>> If your current series needs them to build, I usually prefer to keep
>> it all together, instead of having two different series, and using a
>> Based-on tag. But it's a personal preference, some people prefer to
>> see several series.
> Either, either send them in a separate series or put them at the
> beginning. We are approaching the soft freeze so maybe a separate series
> would be better.
Thank you all for the guide.
I’ll resend #1/#2/#19 as a small standalone fixes series with the Fixes
tags, so it can be picked up independently.
The main series will then be rebased accordingly.
Best regards,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported
2026-03-01 12:33 ` Tao Tang
2026-03-02 10:10 ` Mostafa Saleh
2026-03-02 17:47 ` Pierrick Bouvier
@ 2026-03-02 17:51 ` Eric Auger
2 siblings, 0 replies; 136+ messages in thread
From: Eric Auger @ 2026-03-02 17:51 UTC (permalink / raw)
To: Tao Tang, Mostafa Saleh
Cc: Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum, qemu-devel,
qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On 3/1/26 1:33 PM, Tao Tang wrote:
>
> Hi Mostafa,
>
> On 2026/2/27 PM10:49, Mostafa Saleh wrote:
>> On Sat, Feb 21, 2026 at 06:17:33PM +0800, Tao Tang wrote:
>>> Add a STAGE1_SUPPORTED check in the CMD_CFGI_CD and CMD_CFGI_CD_ALL path
>>> and return CERROR_ILL when stage-1 translation is not implemented,
>>> matching the architecture requirement (IHI 0070G.b, page 176).
>>>
>>> Fixes: 32cfd7f39e08 ("hw/arm/smmuv3: Cache/invalidate config data")
>>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> This is a separate fix, it can be sent standalone to make this series
>> smaller, similarly the first patch.
>
>
> For #1, #2 and #19 commit (this one), since I’m not fully sure about
> the expected process here, should I resend these already Reviewed-by
> fixes as standalone patch respectively right now, and try to get them
> merged first?
>
>
>> Also the "Fixes" comment is not accurate, that was probably broken from
>> the stage-2 implementation which was added later.
>
>
> I'll remove "Fixes" when resending this commit.
>
Better to keep it after fixing it ;-)
Eric
>
>
>> Reviewed-by: Mostafa Saleh <smostafa@google.com>
>>
>> Thanks,
>> Mostafa
>
>
> Thanks for your review.
>
> Tao
>
>
>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported
2026-02-21 10:17 ` [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported Tao Tang
2026-02-25 21:40 ` Pierrick Bouvier
2026-02-27 14:49 ` Mostafa Saleh
@ 2026-03-02 17:55 ` Eric Auger
2 siblings, 0 replies; 136+ messages in thread
From: Eric Auger @ 2026-03-02 17:55 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 2/21/26 11:17 AM, Tao Tang wrote:
> Add a STAGE1_SUPPORTED check in the CMD_CFGI_CD and CMD_CFGI_CD_ALL path
> and return CERROR_ILL when stage-1 translation is not implemented,
> matching the architecture requirement (IHI 0070G.b, page 176).
>
> Fixes: 32cfd7f39e08 ("hw/arm/smmuv3: Cache/invalidate config data")
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index fa09099a09a..d4c58c0c724 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1461,6 +1461,15 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> break;
> }
>
> + /*
> + * This command raises CERROR_ILL when stage 1 is not implemented
> + * according to (IHI 0070G.b) Page 176.
> + */
> + if (!STAGE1_SUPPORTED(s)) {
> + cmd_error = SMMU_CERROR_ILL;
> + break;
> + }
> +
> trace_smmuv3_cmdq_cfgi_cd(sid);
> smmuv3_flush_config(sdev);
> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, sdev, errp)) {
With the fixed fixes tag,
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 20/31] hw/arm/smmu: Make CMDQ invalidation security-state aware
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (18 preceding siblings ...)
2026-02-21 10:17 ` [RFC v4 19/31] hw/arm/smmuv3: Fix CFGI_CD handling when stage-1 is unsupported Tao Tang
@ 2026-02-21 10:17 ` Tao Tang
2026-02-25 21:47 ` Pierrick Bouvier
2026-02-21 10:17 ` [RFC v4 21/31] hw/arm/smmuv3: Add access checks for GERROR_IRQ_CFG registers Tao Tang
` (10 subsequent siblings)
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:17 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Refactor CMDQ invalidation paths to carry security state and apply
cache invalidation per sec_sid instead of globally. Extend common
IOTLB/config invalidation helpers with sec_sid filtering, while keeping
SMMU_SEC_SID_NUM as the full-invalidate mode.
In smmuv3, propagate sec_sid/ssec through CFGI and TLBI handling, and
gate VMID usage on queue stage-2 capability (including SEL2 for secure
CMDQ). Update tracepoints to include ssec for better observability.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmu-common.c | 96 ++++++++++++++++++++++++++++++++----
hw/arm/smmuv3.c | 67 ++++++++++++++++++-------
hw/arm/trace-events | 6 +--
include/hw/arm/smmu-common.h | 8 +--
4 files changed, 144 insertions(+), 33 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index bb43430cc3b..5dece2024a4 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -201,7 +201,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new)
uint8_t tg = (new->granule - 10) / 2;
if (g_hash_table_size(bs->iotlb) >= SMMU_IOTLB_MAX_SIZE) {
- smmu_iotlb_inv_all(bs);
+ smmu_iotlb_inv_all(bs, SMMU_SEC_SID_NUM);
}
*key = smmu_get_iotlb_key(cfg->asid, cfg->s2cfg.vmid, new->entry.iova,
@@ -211,10 +211,23 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new)
g_hash_table_insert(bs->iotlb, key, new);
}
-void smmu_iotlb_inv_all(SMMUState *s)
+static gboolean smmu_hash_remove_by_sec_sid(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
+ SMMUSecSID *sec_sid = (SMMUSecSID *)user_data;
+
+ return SMMU_IOTLB_SEC_SID(*iotlb_key) == *sec_sid;
+}
+
+void smmu_iotlb_inv_all(SMMUState *s, SMMUSecSID sec_sid)
{
trace_smmu_iotlb_inv_all();
- g_hash_table_remove_all(s->iotlb);
+ if (sec_sid == SMMU_SEC_SID_NUM) {
+ g_hash_table_remove_all(s->iotlb);
+ return;
+ }
+ g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_sec_sid, &sec_sid);
}
static gboolean smmu_hash_remove_by_asid_vmid(gpointer key, gpointer value,
@@ -292,6 +305,16 @@ static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
((entry->iova & ~info->mask) == info->iova);
}
+typedef struct SMMUConfigInvRangeInfo {
+ SMMUSIDRange sid_range;
+ SMMUSecSID sec_sid;
+} SMMUConfigInvRangeInfo;
+
+typedef struct SMMUConfigInvSdevInfo {
+ SMMUDevice *sdev;
+ SMMUSecSID sec_sid;
+} SMMUConfigInvSdevInfo;
+
static gboolean
smmu_hash_remove_by_sid_range(gpointer key, gpointer value, gpointer user_data)
{
@@ -307,11 +330,41 @@ smmu_hash_remove_by_sid_range(gpointer key, gpointer value, gpointer user_data)
return true;
}
-void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range)
+static gboolean
+smmu_hash_remove_by_sid_range_sec(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ SMMUConfigKey *config_key = (SMMUConfigKey *)key;
+ SMMUConfigInvRangeInfo *info = (SMMUConfigInvRangeInfo *)user_data;
+ SMMUDevice *sdev = config_key->sdev;
+ uint32_t sid = smmu_get_sid(sdev);
+
+ if (config_key->sec_sid != info->sec_sid) {
+ return false;
+ }
+ if (sid < info->sid_range.start || sid > info->sid_range.end) {
+ return false;
+ }
+ trace_smmu_config_cache_inv(sid);
+ return true;
+}
+
+void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range,
+ SMMUSecSID sec_sid)
{
+ SMMUConfigInvRangeInfo info = {
+ .sid_range = sid_range,
+ .sec_sid = sec_sid,
+ };
+
trace_smmu_configs_inv_sid_range(sid_range.start, sid_range.end);
- g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sid_range,
- &sid_range);
+ if (sec_sid == SMMU_SEC_SID_NUM) {
+ g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sid_range,
+ &sid_range);
+ return;
+ }
+ g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sid_range_sec,
+ &info);
}
static gboolean smmu_hash_remove_by_sdev(gpointer key, gpointer value,
@@ -327,9 +380,35 @@ static gboolean smmu_hash_remove_by_sdev(gpointer key, gpointer value,
return true;
}
-void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev)
+static gboolean smmu_hash_remove_by_sdev_sec(gpointer key, gpointer value,
+ gpointer user_data)
{
- g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sdev, sdev);
+ SMMUConfigKey *config_key = (SMMUConfigKey *)key;
+ SMMUConfigInvSdevInfo *info = (SMMUConfigInvSdevInfo *)user_data;
+
+ if (config_key->sdev != info->sdev) {
+ return false;
+ }
+ if (config_key->sec_sid != info->sec_sid) {
+ return false;
+ }
+ trace_smmu_config_cache_inv(smmu_get_sid(info->sdev));
+ return true;
+}
+
+void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev,
+ SMMUSecSID sec_sid)
+{
+ SMMUConfigInvSdevInfo info = {
+ .sdev = sdev,
+ .sec_sid = sec_sid,
+ };
+
+ if (sec_sid == SMMU_SEC_SID_NUM) {
+ g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sdev, sdev);
+ return;
+ }
+ g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sdev_sec, &info);
}
void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
@@ -1193,4 +1272,3 @@ static void smmu_base_register_types(void)
}
type_init(smmu_base_register_types)
-
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index d4c58c0c724..29e862b8ae3 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -959,12 +959,13 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event,
return cfg;
}
-static void smmuv3_flush_config(SMMUDevice *sdev)
+/* Flush all config caches when sec_sid == SMMU_SEC_SID_NUM */
+static void smmuv3_flush_config(SMMUDevice *sdev, SMMUSecSID sec_sid)
{
SMMUv3State *s = sdev->smmu;
SMMUState *bc = &s->smmu_state;
- smmu_configs_inv_sdev(bc, sdev);
+ smmu_configs_inv_sdev(bc, sdev, sec_sid);
}
/* Do translation with TLB lookup. */
@@ -1289,7 +1290,7 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
}
static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
- SMMUSecSID sec_sid)
+ SMMUSecSID sec_sid, bool use_vmid)
{
dma_addr_t end, addr = CMD_ADDR(cmd);
uint8_t type = CMD_TYPE(cmd);
@@ -1302,10 +1303,8 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
uint64_t num_pages;
uint8_t granule;
int asid = -1;
- SMMUv3State *smmuv3 = ARM_SMMUV3(s);
- /* Only consider VMID if stage-2 is supported. */
- if (STAGE2_SUPPORTED(smmuv3)) {
+ if (use_vmid) {
vmid = CMD_VMID(cmd);
}
@@ -1351,6 +1350,25 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
}
}
+static inline bool smmu_cmdq_stage2_supported(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ /* IDR0.S2P: Stage 2 translation supported */
+ bool s2p = STAGE2_SUPPORTED(s);
+ if (!s2p) {
+ return false;
+ }
+
+ /*
+ * For Secure Command queue, Secure stage 2 is additionally gated by SEL2
+ * (SEL2 is 0 if S2P is 0).
+ */
+ if (sec_sid == SMMU_SEC_SID_S) {
+ return FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1, SEL2);
+ }
+
+ return true;
+}
+
static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
{
SMMUState *bs = ARM_SMMU(s);
@@ -1362,6 +1380,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
AddressSpace *as = smmu_get_address_space(bs, sec_sid);
/* Secure AddressSpace must be available, assert if not. */
g_assert(as);
+ bool queue_stage2_supported = smmu_cmdq_stage2_supported(s, sec_sid);
if (!smmuv3_cmdq_enabled(s, sec_sid)) {
return 0;
@@ -1376,6 +1395,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
while (!smmuv3_q_empty(q)) {
uint32_t pending = bank->gerror ^ bank->gerrorn;
Cmd cmd;
+ SMMUSecSID ssec = SMMU_SEC_SID_NS;
trace_smmuv3_cmdq_consume(sec_sid, Q_PROD(q), Q_CONS(q),
Q_PROD_WRAP(q), Q_CONS_WRAP(q));
@@ -1399,6 +1419,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
cmd_error = SMMU_CERROR_ILL;
break;
}
+ ssec = SMMU_SEC_SID_S;
}
type = CMD_TYPE(&cmd);
@@ -1424,12 +1445,12 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
break;
}
- trace_smmuv3_cmdq_cfgi_ste(sid);
+ trace_smmuv3_cmdq_cfgi_ste(ssec, sid);
if (!smmuv3_accel_install_ste(s, sdev, sid, errp)) {
cmd_error = SMMU_CERROR_ILL;
break;
}
- smmuv3_flush_config(sdev);
+ smmuv3_flush_config(sdev, ssec);
break;
}
@@ -1443,12 +1464,12 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
sid_range.start = sid & ~mask;
sid_range.end = sid_range.start + mask;
- trace_smmuv3_cmdq_cfgi_ste_range(sid_range.start, sid_range.end);
+ trace_smmuv3_cmdq_cfgi_ste_range(ssec, sid_range.start, sid_range.end);
if (!smmuv3_accel_install_ste_range(s, &sid_range, errp)) {
cmd_error = SMMU_CERROR_ILL;
break;
}
- smmu_configs_inv_sid_range(bs, sid_range);
+ smmu_configs_inv_sid_range(bs, sid_range, ssec);
break;
}
case SMMU_CMD_CFGI_CD:
@@ -1470,8 +1491,8 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
break;
}
- trace_smmuv3_cmdq_cfgi_cd(sid);
- smmuv3_flush_config(sdev);
+ trace_smmuv3_cmdq_cfgi_cd(ssec, sid);
+ smmuv3_flush_config(sdev, ssec);
if (!smmuv3_accel_issue_inv_cmd(s, &cmd, sdev, errp)) {
cmd_error = SMMU_CERROR_ILL;
break;
@@ -1492,7 +1513,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
* VMID is only matched when stage 2 is supported, otherwise set it
* to -1 as the value used for stage-1 only VMIDs.
*/
- if (STAGE2_SUPPORTED(s)) {
+ if (queue_stage2_supported) {
vmid = CMD_VMID(&cmd);
}
@@ -1518,18 +1539,27 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
* If stage-2 is supported, invalidate for this VMID only, otherwise
* invalidate the whole thing.
*/
- if (STAGE2_SUPPORTED(s)) {
+ if (queue_stage2_supported) {
vmid = CMD_VMID(&cmd);
trace_smmuv3_cmdq_tlbi_nh(sec_sid, vmid);
smmu_iotlb_inv_vmid_s1(bs, vmid, sec_sid);
break;
}
- QEMU_FALLTHROUGH;
+ trace_smmuv3_cmdq_tlbi_nh(sec_sid, vmid);
+ smmu_inv_notifiers_all(&s->smmu_state);
+ smmu_iotlb_inv_all(bs, sec_sid);
+ break;
}
case SMMU_CMD_TLBI_NSNH_ALL:
trace_smmuv3_cmdq_tlbi_nsnh();
smmu_inv_notifiers_all(&s->smmu_state);
- smmu_iotlb_inv_all(bs);
+ /*
+ * According to (IHI 0070G.b) 4.4.4.1 CMD_TLBI_NSNH_ALL, Page 194:
+ * "When issuing to the Realm programming interface, even though
+ * this command has NS in its name, it only applies to Realm entries."
+ */
+ smmu_iotlb_inv_all(bs, sec_sid > SMMU_SEC_SID_S ?
+ sec_sid : SMMU_SEC_SID_NS);
if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
cmd_error = SMMU_CERROR_ILL;
break;
@@ -1541,7 +1571,8 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
cmd_error = SMMU_CERROR_ILL;
break;
}
- smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1, SMMU_SEC_SID_NS);
+ smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1, sec_sid,
+ queue_stage2_supported);
if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
cmd_error = SMMU_CERROR_ILL;
break;
@@ -1570,7 +1601,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
* As currently only either s1 or s2 are supported
* we can reuse same function for s2.
*/
- smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2, SMMU_SEC_SID_NS);
+ smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2, SMMU_SEC_SID_NS, true);
break;
case SMMU_CMD_ATC_INV:
{
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index ca8485c96af..64f308a8d35 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -51,9 +51,9 @@ smmuv3_translate_success(const char *n, uint16_t sid, uint64_t iova, uint64_t tr
smmuv3_get_cd(uint64_t addr) "CD addr: 0x%"PRIx64
smmuv3_decode_cd(uint32_t oas) "oas=%d"
smmuv3_decode_cd_tt(int i, uint32_t tsz, uint64_t ttb, uint32_t granule_sz, bool had) "TT[%d]:tsz:%d ttb:0x%"PRIx64" granule_sz:%d had:%d"
-smmuv3_cmdq_cfgi_ste(int streamid) "streamid= 0x%x"
-smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%x - end=0x%x"
-smmuv3_cmdq_cfgi_cd(uint32_t sid) "sid=0x%x"
+smmuv3_cmdq_cfgi_ste(int ssec, int streamid) "ssec=%d streamid= 0x%x"
+smmuv3_cmdq_cfgi_ste_range(int ssec, int start, int end) "ssec=%d start=0x%x - end=0x%x"
+smmuv3_cmdq_cfgi_cd(int ssec, uint32_t sid) "ssec=%d sid=0x%x"
smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
smmuv3_range_inval(int sec_sid, int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf, int stage) "sec_sid=%d vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d stage=%d"
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index 7d1d0936921..d05cf6ae53b 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -259,7 +259,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *entry);
SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
uint8_t tg, uint8_t level, SMMUSecSID sec_sid);
SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID sec_sid);
-void smmu_iotlb_inv_all(SMMUState *s);
+void smmu_iotlb_inv_all(SMMUState *s, SMMUSecSID sec_sid);
void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid,
SMMUSecSID sec_sid);
void smmu_iotlb_inv_vmid(SMMUState *s, int vmid, SMMUSecSID sec_sid);
@@ -270,8 +270,10 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
uint64_t num_pages, uint8_t ttl,
SMMUSecSID sec_sid);
-void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range);
-void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev);
+void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range,
+ SMMUSecSID sec_sid);
+void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev,
+ SMMUSecSID sec_sid);
/* Unmap the range of all the notifiers registered to any IOMMU mr */
void smmu_inv_notifiers_all(SMMUState *s);
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 20/31] hw/arm/smmu: Make CMDQ invalidation security-state aware
2026-02-21 10:17 ` [RFC v4 20/31] hw/arm/smmu: Make CMDQ invalidation security-state aware Tao Tang
@ 2026-02-25 21:47 ` Pierrick Bouvier
2026-02-27 15:41 ` Tao Tang
0 siblings, 1 reply; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:47 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:17 AM, Tao Tang wrote:
> Refactor CMDQ invalidation paths to carry security state and apply
> cache invalidation per sec_sid instead of globally. Extend common
> IOTLB/config invalidation helpers with sec_sid filtering, while keeping
> SMMU_SEC_SID_NUM as the full-invalidate mode.
>
> In smmuv3, propagate sec_sid/ssec through CFGI and TLBI handling, and
> gate VMID usage on queue stage-2 capability (including SEL2 for secure
> CMDQ). Update tracepoints to include ssec for better observability.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 96 ++++++++++++++++++++++++++++++++----
> hw/arm/smmuv3.c | 67 ++++++++++++++++++-------
> hw/arm/trace-events | 6 +--
> include/hw/arm/smmu-common.h | 8 +--
> 4 files changed, 144 insertions(+), 33 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index bb43430cc3b..5dece2024a4 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -201,7 +201,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new)
> uint8_t tg = (new->granule - 10) / 2;
>
> if (g_hash_table_size(bs->iotlb) >= SMMU_IOTLB_MAX_SIZE) {
> - smmu_iotlb_inv_all(bs);
> + smmu_iotlb_inv_all(bs, SMMU_SEC_SID_NUM);
> }
>
> *key = smmu_get_iotlb_key(cfg->asid, cfg->s2cfg.vmid, new->entry.iova,
> @@ -211,10 +211,23 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *new)
> g_hash_table_insert(bs->iotlb, key, new);
> }
>
> -void smmu_iotlb_inv_all(SMMUState *s)
> +static gboolean smmu_hash_remove_by_sec_sid(gpointer key, gpointer value,
> + gpointer user_data)
> +{
> + SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
> + SMMUSecSID *sec_sid = (SMMUSecSID *)user_data;
> +
> + return SMMU_IOTLB_SEC_SID(*iotlb_key) == *sec_sid;
> +}
> +
> +void smmu_iotlb_inv_all(SMMUState *s, SMMUSecSID sec_sid)
> {
> trace_smmu_iotlb_inv_all();
> - g_hash_table_remove_all(s->iotlb);
> + if (sec_sid == SMMU_SEC_SID_NUM) {
> + g_hash_table_remove_all(s->iotlb);
> + return;
> + }
> + g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_sec_sid, &sec_sid);
> }
>
> static gboolean smmu_hash_remove_by_asid_vmid(gpointer key, gpointer value,
> @@ -292,6 +305,16 @@ static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
> ((entry->iova & ~info->mask) == info->iova);
> }
>
> +typedef struct SMMUConfigInvRangeInfo {
> + SMMUSIDRange sid_range;
> + SMMUSecSID sec_sid;
> +} SMMUConfigInvRangeInfo;
> +
> +typedef struct SMMUConfigInvSdevInfo {
> + SMMUDevice *sdev;
> + SMMUSecSID sec_sid;
> +} SMMUConfigInvSdevInfo;
> +
> static gboolean
> smmu_hash_remove_by_sid_range(gpointer key, gpointer value, gpointer user_data)
> {
> @@ -307,11 +330,41 @@ smmu_hash_remove_by_sid_range(gpointer key, gpointer value, gpointer user_data)
> return true;
> }
>
> -void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range)
> +static gboolean
> +smmu_hash_remove_by_sid_range_sec(gpointer key, gpointer value,
> + gpointer user_data)
> +{
> + SMMUConfigKey *config_key = (SMMUConfigKey *)key;
> + SMMUConfigInvRangeInfo *info = (SMMUConfigInvRangeInfo *)user_data;
> + SMMUDevice *sdev = config_key->sdev;
> + uint32_t sid = smmu_get_sid(sdev);
> +
> + if (config_key->sec_sid != info->sec_sid) {
> + return false;
> + }
> + if (sid < info->sid_range.start || sid > info->sid_range.end) {
> + return false;
> + }
> + trace_smmu_config_cache_inv(sid);
> + return true;
> +}
> +
> +void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range,
> + SMMUSecSID sec_sid)
> {
> + SMMUConfigInvRangeInfo info = {
> + .sid_range = sid_range,
> + .sec_sid = sec_sid,
> + };
> +
> trace_smmu_configs_inv_sid_range(sid_range.start, sid_range.end);
> - g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sid_range,
> - &sid_range);
> + if (sec_sid == SMMU_SEC_SID_NUM) {
> + g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sid_range,
> + &sid_range);
> + return;
> + }
> + g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sid_range_sec,
> + &info);
> }
>
> static gboolean smmu_hash_remove_by_sdev(gpointer key, gpointer value,
> @@ -327,9 +380,35 @@ static gboolean smmu_hash_remove_by_sdev(gpointer key, gpointer value,
> return true;
> }
>
> -void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev)
> +static gboolean smmu_hash_remove_by_sdev_sec(gpointer key, gpointer value,
> + gpointer user_data)
> {
> - g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sdev, sdev);
> + SMMUConfigKey *config_key = (SMMUConfigKey *)key;
> + SMMUConfigInvSdevInfo *info = (SMMUConfigInvSdevInfo *)user_data;
> +
> + if (config_key->sdev != info->sdev) {
> + return false;
> + }
> + if (config_key->sec_sid != info->sec_sid) {
> + return false;
> + }
> + trace_smmu_config_cache_inv(smmu_get_sid(info->sdev));
> + return true;
> +}
> +
> +void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev,
> + SMMUSecSID sec_sid)
> +{
> + SMMUConfigInvSdevInfo info = {
> + .sdev = sdev,
> + .sec_sid = sec_sid,
> + };
> +
> + if (sec_sid == SMMU_SEC_SID_NUM) {
> + g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sdev, sdev);
> + return;
> + }
> + g_hash_table_foreach_remove(s->configs, smmu_hash_remove_by_sdev_sec, &info);
> }
>
> void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> @@ -1193,4 +1272,3 @@ static void smmu_base_register_types(void)
> }
>
> type_init(smmu_base_register_types)
> -
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index d4c58c0c724..29e862b8ae3 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -959,12 +959,13 @@ static SMMUTransCfg *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event,
> return cfg;
> }
>
> -static void smmuv3_flush_config(SMMUDevice *sdev)
> +/* Flush all config caches when sec_sid == SMMU_SEC_SID_NUM */
> +static void smmuv3_flush_config(SMMUDevice *sdev, SMMUSecSID sec_sid)
> {
> SMMUv3State *s = sdev->smmu;
> SMMUState *bc = &s->smmu_state;
>
> - smmu_configs_inv_sdev(bc, sdev);
> + smmu_configs_inv_sdev(bc, sdev, sec_sid);
> }
>
> /* Do translation with TLB lookup. */
> @@ -1289,7 +1290,7 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
> }
>
> static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
> - SMMUSecSID sec_sid)
> + SMMUSecSID sec_sid, bool use_vmid)
> {
> dma_addr_t end, addr = CMD_ADDR(cmd);
> uint8_t type = CMD_TYPE(cmd);
> @@ -1302,10 +1303,8 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
> uint64_t num_pages;
> uint8_t granule;
> int asid = -1;
> - SMMUv3State *smmuv3 = ARM_SMMUV3(s);
>
> - /* Only consider VMID if stage-2 is supported. */
> - if (STAGE2_SUPPORTED(smmuv3)) {
> + if (use_vmid) {
> vmid = CMD_VMID(cmd);
> }
>
> @@ -1351,6 +1350,25 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage,
> }
> }
>
> +static inline bool smmu_cmdq_stage2_supported(SMMUv3State *s, SMMUSecSID sec_sid)
> +{
> + /* IDR0.S2P: Stage 2 translation supported */
> + bool s2p = STAGE2_SUPPORTED(s);
> + if (!s2p) {
> + return false;
> + }
> +
> + /*
> + * For Secure Command queue, Secure stage 2 is additionally gated by SEL2
> + * (SEL2 is 0 if S2P is 0).
> + */
> + if (sec_sid == SMMU_SEC_SID_S) {
> + return FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1, SEL2);
> + }
> +
> + return true;
> +}
> +
> static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> {
> SMMUState *bs = ARM_SMMU(s);
> @@ -1362,6 +1380,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> AddressSpace *as = smmu_get_address_space(bs, sec_sid);
> /* Secure AddressSpace must be available, assert if not. */
> g_assert(as);
> + bool queue_stage2_supported = smmu_cmdq_stage2_supported(s, sec_sid);
>
> if (!smmuv3_cmdq_enabled(s, sec_sid)) {
> return 0;
> @@ -1376,6 +1395,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> while (!smmuv3_q_empty(q)) {
> uint32_t pending = bank->gerror ^ bank->gerrorn;
> Cmd cmd;
> + SMMUSecSID ssec = SMMU_SEC_SID_NS;
>
> trace_smmuv3_cmdq_consume(sec_sid, Q_PROD(q), Q_CONS(q),
> Q_PROD_WRAP(q), Q_CONS_WRAP(q));
> @@ -1399,6 +1419,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> cmd_error = SMMU_CERROR_ILL;
> break;
> }
> + ssec = SMMU_SEC_SID_S;
> }
>
> type = CMD_TYPE(&cmd);
> @@ -1424,12 +1445,12 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> break;
> }
>
> - trace_smmuv3_cmdq_cfgi_ste(sid);
> + trace_smmuv3_cmdq_cfgi_ste(ssec, sid);
> if (!smmuv3_accel_install_ste(s, sdev, sid, errp)) {
> cmd_error = SMMU_CERROR_ILL;
> break;
> }
> - smmuv3_flush_config(sdev);
> + smmuv3_flush_config(sdev, ssec);
>
> break;
> }
> @@ -1443,12 +1464,12 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> sid_range.start = sid & ~mask;
> sid_range.end = sid_range.start + mask;
>
> - trace_smmuv3_cmdq_cfgi_ste_range(sid_range.start, sid_range.end);
> + trace_smmuv3_cmdq_cfgi_ste_range(ssec, sid_range.start, sid_range.end);
> if (!smmuv3_accel_install_ste_range(s, &sid_range, errp)) {
> cmd_error = SMMU_CERROR_ILL;
> break;
> }
> - smmu_configs_inv_sid_range(bs, sid_range);
> + smmu_configs_inv_sid_range(bs, sid_range, ssec);
> break;
> }
> case SMMU_CMD_CFGI_CD:
> @@ -1470,8 +1491,8 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> break;
> }
>
> - trace_smmuv3_cmdq_cfgi_cd(sid);
> - smmuv3_flush_config(sdev);
> + trace_smmuv3_cmdq_cfgi_cd(ssec, sid);
> + smmuv3_flush_config(sdev, ssec);
> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, sdev, errp)) {
> cmd_error = SMMU_CERROR_ILL;
> break;
> @@ -1492,7 +1513,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> * VMID is only matched when stage 2 is supported, otherwise set it
> * to -1 as the value used for stage-1 only VMIDs.
> */
> - if (STAGE2_SUPPORTED(s)) {
> + if (queue_stage2_supported) {
> vmid = CMD_VMID(&cmd);
> }
>
> @@ -1518,18 +1539,27 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> * If stage-2 is supported, invalidate for this VMID only, otherwise
> * invalidate the whole thing.
> */
> - if (STAGE2_SUPPORTED(s)) {
> + if (queue_stage2_supported) {
> vmid = CMD_VMID(&cmd);
> trace_smmuv3_cmdq_tlbi_nh(sec_sid, vmid);
> smmu_iotlb_inv_vmid_s1(bs, vmid, sec_sid);
> break;
> }
> - QEMU_FALLTHROUGH;
> + trace_smmuv3_cmdq_tlbi_nh(sec_sid, vmid);
> + smmu_inv_notifiers_all(&s->smmu_state);
> + smmu_iotlb_inv_all(bs, sec_sid);
> + break;
> }
> case SMMU_CMD_TLBI_NSNH_ALL:
> trace_smmuv3_cmdq_tlbi_nsnh();
> smmu_inv_notifiers_all(&s->smmu_state);
> - smmu_iotlb_inv_all(bs);
> + /*
> + * According to (IHI 0070G.b) 4.4.4.1 CMD_TLBI_NSNH_ALL, Page 194:
> + * "When issuing to the Realm programming interface, even though
> + * this command has NS in its name, it only applies to Realm entries."
> + */
> + smmu_iotlb_inv_all(bs, sec_sid > SMMU_SEC_SID_S ?
> + sec_sid : SMMU_SEC_SID_NS);
> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
> cmd_error = SMMU_CERROR_ILL;
> break;
> @@ -1541,7 +1571,8 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> cmd_error = SMMU_CERROR_ILL;
> break;
> }
> - smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1, SMMU_SEC_SID_NS);
> + smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1, sec_sid,
> + queue_stage2_supported);
> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
> cmd_error = SMMU_CERROR_ILL;
> break;
> @@ -1570,7 +1601,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> * As currently only either s1 or s2 are supported
> * we can reuse same function for s2.
> */
> - smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2, SMMU_SEC_SID_NS);
> + smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2, SMMU_SEC_SID_NS, true);
> break;
> case SMMU_CMD_ATC_INV:
> {
> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> index ca8485c96af..64f308a8d35 100644
> --- a/hw/arm/trace-events
> +++ b/hw/arm/trace-events
> @@ -51,9 +51,9 @@ smmuv3_translate_success(const char *n, uint16_t sid, uint64_t iova, uint64_t tr
> smmuv3_get_cd(uint64_t addr) "CD addr: 0x%"PRIx64
> smmuv3_decode_cd(uint32_t oas) "oas=%d"
> smmuv3_decode_cd_tt(int i, uint32_t tsz, uint64_t ttb, uint32_t granule_sz, bool had) "TT[%d]:tsz:%d ttb:0x%"PRIx64" granule_sz:%d had:%d"
> -smmuv3_cmdq_cfgi_ste(int streamid) "streamid= 0x%x"
> -smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%x - end=0x%x"
> -smmuv3_cmdq_cfgi_cd(uint32_t sid) "sid=0x%x"
> +smmuv3_cmdq_cfgi_ste(int ssec, int streamid) "ssec=%d streamid= 0x%x"
> +smmuv3_cmdq_cfgi_ste_range(int ssec, int start, int end) "ssec=%d start=0x%x - end=0x%x"
> +smmuv3_cmdq_cfgi_cd(int ssec, uint32_t sid) "ssec=%d sid=0x%x"
> smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache HIT for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
> smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t perc) "Config cache MISS for sid=0x%x (hits=%d, misses=%d, hit rate=%d)"
> smmuv3_range_inval(int sec_sid, int vmid, int asid, uint64_t addr, uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf, int stage) "sec_sid=%d vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d stage=%d"
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index 7d1d0936921..d05cf6ae53b 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -259,7 +259,7 @@ void smmu_iotlb_insert(SMMUState *bs, SMMUTransCfg *cfg, SMMUTLBEntry *entry);
> SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> uint8_t tg, uint8_t level, SMMUSecSID sec_sid);
> SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID sec_sid);
> -void smmu_iotlb_inv_all(SMMUState *s);
> +void smmu_iotlb_inv_all(SMMUState *s, SMMUSecSID sec_sid);
> void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid,
> SMMUSecSID sec_sid);
> void smmu_iotlb_inv_vmid(SMMUState *s, int vmid, SMMUSecSID sec_sid);
> @@ -270,8 +270,10 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
> uint64_t num_pages, uint8_t ttl,
> SMMUSecSID sec_sid);
> -void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range);
> -void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev);
> +void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range,
> + SMMUSecSID sec_sid);
> +void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev,
> + SMMUSecSID sec_sid);
> /* Unmap the range of all the notifiers registered to any IOMMU mr */
> void smmu_inv_notifiers_all(SMMUState *s);
>
Looks ok overall.
Using SMMU_SEC_SID_NUM as a special value to trigger all
flush/invalidate works, but it's a bit surprising to read to be honest.
It could be more explicit to introduce the two next functions:
smmu_iotlb_inv_by_sec_sid(SMMUState *s, SMMUSecSID sec_sid)
smmuv3_flush_config_by_sec_sid(SMMUDevice *sdev, SMMUSecSID sec_sid)
And in addition:
smmu_iotlb_inv_all with the current semantic (invalidate all entries).
Same for smmuv3_flush_config (flush all configs).
What do you think about it?
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 20/31] hw/arm/smmu: Make CMDQ invalidation security-state aware
2026-02-25 21:47 ` Pierrick Bouvier
@ 2026-02-27 15:41 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-27 15:41 UTC (permalink / raw)
To: Pierrick Bouvier, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
Hi Pierrick,
On 2026/2/26 05:47, Pierrick Bouvier wrote:
> On 2/21/26 2:17 AM, Tao Tang wrote:
>> Refactor CMDQ invalidation paths to carry security state and apply
>> cache invalidation per sec_sid instead of globally. Extend common
>> IOTLB/config invalidation helpers with sec_sid filtering, while keeping
>> SMMU_SEC_SID_NUM as the full-invalidate mode.
>>
>> In smmuv3, propagate sec_sid/ssec through CFGI and TLBI handling, and
>> gate VMID usage on queue stage-2 capability (including SEL2 for secure
>> CMDQ). Update tracepoints to include ssec for better observability.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmu-common.c | 96 ++++++++++++++++++++++++++++++++----
>> hw/arm/smmuv3.c | 67 ++++++++++++++++++-------
>> hw/arm/trace-events | 6 +--
>> include/hw/arm/smmu-common.h | 8 +--
>> 4 files changed, 144 insertions(+), 33 deletions(-)
>>
>> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
>> index bb43430cc3b..5dece2024a4 100644
>> --- a/hw/arm/smmu-common.c
>> +++ b/hw/arm/smmu-common.c
>> @@ -201,7 +201,7 @@ void smmu_iotlb_insert(SMMUState *bs,
>> SMMUTransCfg *cfg, SMMUTLBEntry *new)
>> uint8_t tg = (new->granule - 10) / 2;
>> if (g_hash_table_size(bs->iotlb) >= SMMU_IOTLB_MAX_SIZE) {
>> - smmu_iotlb_inv_all(bs);
>> + smmu_iotlb_inv_all(bs, SMMU_SEC_SID_NUM);
>> }
>> *key = smmu_get_iotlb_key(cfg->asid, cfg->s2cfg.vmid,
>> new->entry.iova,
>> @@ -211,10 +211,23 @@ void smmu_iotlb_insert(SMMUState *bs,
>> SMMUTransCfg *cfg, SMMUTLBEntry *new)
>> g_hash_table_insert(bs->iotlb, key, new);
>> }
>> -void smmu_iotlb_inv_all(SMMUState *s)
>> +static gboolean smmu_hash_remove_by_sec_sid(gpointer key, gpointer
>> value,
>> + gpointer user_data)
>> +{
>> + SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
>> + SMMUSecSID *sec_sid = (SMMUSecSID *)user_data;
>> +
>> + return SMMU_IOTLB_SEC_SID(*iotlb_key) == *sec_sid;
>> +}
>> +
>> +void smmu_iotlb_inv_all(SMMUState *s, SMMUSecSID sec_sid)
>> {
>> trace_smmu_iotlb_inv_all();
>> - g_hash_table_remove_all(s->iotlb);
>> + if (sec_sid == SMMU_SEC_SID_NUM) {
>> + g_hash_table_remove_all(s->iotlb);
>> + return;
>> + }
>> + g_hash_table_foreach_remove(s->iotlb,
>> smmu_hash_remove_by_sec_sid, &sec_sid);
>> }
>> static gboolean smmu_hash_remove_by_asid_vmid(gpointer key,
>> gpointer value,
>> @@ -292,6 +305,16 @@ static gboolean
>> smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
>> ((entry->iova & ~info->mask) == info->iova);
>> }
>> +typedef struct SMMUConfigInvRangeInfo {
>> + SMMUSIDRange sid_range;
>> + SMMUSecSID sec_sid;
>> +} SMMUConfigInvRangeInfo;
>> +
>> +typedef struct SMMUConfigInvSdevInfo {
>> + SMMUDevice *sdev;
>> + SMMUSecSID sec_sid;
>> +} SMMUConfigInvSdevInfo;
>> +
>> static gboolean
>> smmu_hash_remove_by_sid_range(gpointer key, gpointer value,
>> gpointer user_data)
>> {
>> @@ -307,11 +330,41 @@ smmu_hash_remove_by_sid_range(gpointer key,
>> gpointer value, gpointer user_data)
>> return true;
>> }
>> -void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range)
>> +static gboolean
>> +smmu_hash_remove_by_sid_range_sec(gpointer key, gpointer value,
>> + gpointer user_data)
>> +{
>> + SMMUConfigKey *config_key = (SMMUConfigKey *)key;
>> + SMMUConfigInvRangeInfo *info = (SMMUConfigInvRangeInfo *)user_data;
>> + SMMUDevice *sdev = config_key->sdev;
>> + uint32_t sid = smmu_get_sid(sdev);
>> +
>> + if (config_key->sec_sid != info->sec_sid) {
>> + return false;
>> + }
>> + if (sid < info->sid_range.start || sid > info->sid_range.end) {
>> + return false;
>> + }
>> + trace_smmu_config_cache_inv(sid);
>> + return true;
>> +}
>> +
>> +void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range,
>> + SMMUSecSID sec_sid)
>> {
>> + SMMUConfigInvRangeInfo info = {
>> + .sid_range = sid_range,
>> + .sec_sid = sec_sid,
>> + };
>> +
>> trace_smmu_configs_inv_sid_range(sid_range.start, sid_range.end);
>> - g_hash_table_foreach_remove(s->configs,
>> smmu_hash_remove_by_sid_range,
>> - &sid_range);
>> + if (sec_sid == SMMU_SEC_SID_NUM) {
>> + g_hash_table_foreach_remove(s->configs,
>> smmu_hash_remove_by_sid_range,
>> + &sid_range);
>> + return;
>> + }
>> + g_hash_table_foreach_remove(s->configs,
>> smmu_hash_remove_by_sid_range_sec,
>> + &info);
>> }
>> static gboolean smmu_hash_remove_by_sdev(gpointer key, gpointer
>> value,
>> @@ -327,9 +380,35 @@ static gboolean
>> smmu_hash_remove_by_sdev(gpointer key, gpointer value,
>> return true;
>> }
>> -void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev)
>> +static gboolean smmu_hash_remove_by_sdev_sec(gpointer key, gpointer
>> value,
>> + gpointer user_data)
>> {
>> - g_hash_table_foreach_remove(s->configs,
>> smmu_hash_remove_by_sdev, sdev);
>> + SMMUConfigKey *config_key = (SMMUConfigKey *)key;
>> + SMMUConfigInvSdevInfo *info = (SMMUConfigInvSdevInfo *)user_data;
>> +
>> + if (config_key->sdev != info->sdev) {
>> + return false;
>> + }
>> + if (config_key->sec_sid != info->sec_sid) {
>> + return false;
>> + }
>> + trace_smmu_config_cache_inv(smmu_get_sid(info->sdev));
>> + return true;
>> +}
>> +
>> +void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev,
>> + SMMUSecSID sec_sid)
>> +{
>> + SMMUConfigInvSdevInfo info = {
>> + .sdev = sdev,
>> + .sec_sid = sec_sid,
>> + };
>> +
>> + if (sec_sid == SMMU_SEC_SID_NUM) {
>> + g_hash_table_foreach_remove(s->configs,
>> smmu_hash_remove_by_sdev, sdev);
>> + return;
>> + }
>> + g_hash_table_foreach_remove(s->configs,
>> smmu_hash_remove_by_sdev_sec, &info);
>> }
>> void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid,
>> dma_addr_t iova,
>> @@ -1193,4 +1272,3 @@ static void smmu_base_register_types(void)
>> }
>> type_init(smmu_base_register_types)
>> -
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index d4c58c0c724..29e862b8ae3 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -959,12 +959,13 @@ static SMMUTransCfg
>> *smmuv3_get_config(SMMUDevice *sdev, SMMUEventInfo *event,
>> return cfg;
>> }
>> -static void smmuv3_flush_config(SMMUDevice *sdev)
>> +/* Flush all config caches when sec_sid == SMMU_SEC_SID_NUM */
>> +static void smmuv3_flush_config(SMMUDevice *sdev, SMMUSecSID sec_sid)
>> {
>> SMMUv3State *s = sdev->smmu;
>> SMMUState *bc = &s->smmu_state;
>> - smmu_configs_inv_sdev(bc, sdev);
>> + smmu_configs_inv_sdev(bc, sdev, sec_sid);
>> }
>> /* Do translation with TLB lookup. */
>> @@ -1289,7 +1290,7 @@ static void smmuv3_inv_notifiers_iova(SMMUState
>> *s, int asid, int vmid,
>> }
>> static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage
>> stage,
>> - SMMUSecSID sec_sid)
>> + SMMUSecSID sec_sid, bool use_vmid)
>> {
>> dma_addr_t end, addr = CMD_ADDR(cmd);
>> uint8_t type = CMD_TYPE(cmd);
>> @@ -1302,10 +1303,8 @@ static void smmuv3_range_inval(SMMUState *s,
>> Cmd *cmd, SMMUStage stage,
>> uint64_t num_pages;
>> uint8_t granule;
>> int asid = -1;
>> - SMMUv3State *smmuv3 = ARM_SMMUV3(s);
>> - /* Only consider VMID if stage-2 is supported. */
>> - if (STAGE2_SUPPORTED(smmuv3)) {
>> + if (use_vmid) {
>> vmid = CMD_VMID(cmd);
>> }
>> @@ -1351,6 +1350,25 @@ static void smmuv3_range_inval(SMMUState *s,
>> Cmd *cmd, SMMUStage stage,
>> }
>> }
>> +static inline bool smmu_cmdq_stage2_supported(SMMUv3State *s,
>> SMMUSecSID sec_sid)
>> +{
>> + /* IDR0.S2P: Stage 2 translation supported */
>> + bool s2p = STAGE2_SUPPORTED(s);
>> + if (!s2p) {
>> + return false;
>> + }
>> +
>> + /*
>> + * For Secure Command queue, Secure stage 2 is additionally
>> gated by SEL2
>> + * (SEL2 is 0 if S2P is 0).
>> + */
>> + if (sec_sid == SMMU_SEC_SID_S) {
>> + return FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1,
>> SEL2);
>> + }
>> +
>> + return true;
>> +}
>> +
>> static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp,
>> SMMUSecSID sec_sid)
>> {
>> SMMUState *bs = ARM_SMMU(s);
>> @@ -1362,6 +1380,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s,
>> Error **errp, SMMUSecSID sec_sid)
>> AddressSpace *as = smmu_get_address_space(bs, sec_sid);
>> /* Secure AddressSpace must be available, assert if not. */
>> g_assert(as);
>> + bool queue_stage2_supported = smmu_cmdq_stage2_supported(s,
>> sec_sid);
>> if (!smmuv3_cmdq_enabled(s, sec_sid)) {
>> return 0;
>> @@ -1376,6 +1395,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s,
>> Error **errp, SMMUSecSID sec_sid)
>> while (!smmuv3_q_empty(q)) {
>> uint32_t pending = bank->gerror ^ bank->gerrorn;
>> Cmd cmd;
>> + SMMUSecSID ssec = SMMU_SEC_SID_NS;
>> trace_smmuv3_cmdq_consume(sec_sid, Q_PROD(q), Q_CONS(q),
>> Q_PROD_WRAP(q), Q_CONS_WRAP(q));
>> @@ -1399,6 +1419,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s,
>> Error **errp, SMMUSecSID sec_sid)
>> cmd_error = SMMU_CERROR_ILL;
>> break;
>> }
>> + ssec = SMMU_SEC_SID_S;
>> }
>> type = CMD_TYPE(&cmd);
>> @@ -1424,12 +1445,12 @@ static int smmuv3_cmdq_consume(SMMUv3State
>> *s, Error **errp, SMMUSecSID sec_sid)
>> break;
>> }
>> - trace_smmuv3_cmdq_cfgi_ste(sid);
>> + trace_smmuv3_cmdq_cfgi_ste(ssec, sid);
>> if (!smmuv3_accel_install_ste(s, sdev, sid, errp)) {
>> cmd_error = SMMU_CERROR_ILL;
>> break;
>> }
>> - smmuv3_flush_config(sdev);
>> + smmuv3_flush_config(sdev, ssec);
>> break;
>> }
>> @@ -1443,12 +1464,12 @@ static int smmuv3_cmdq_consume(SMMUv3State
>> *s, Error **errp, SMMUSecSID sec_sid)
>> sid_range.start = sid & ~mask;
>> sid_range.end = sid_range.start + mask;
>> - trace_smmuv3_cmdq_cfgi_ste_range(sid_range.start,
>> sid_range.end);
>> + trace_smmuv3_cmdq_cfgi_ste_range(ssec, sid_range.start,
>> sid_range.end);
>> if (!smmuv3_accel_install_ste_range(s, &sid_range,
>> errp)) {
>> cmd_error = SMMU_CERROR_ILL;
>> break;
>> }
>> - smmu_configs_inv_sid_range(bs, sid_range);
>> + smmu_configs_inv_sid_range(bs, sid_range, ssec);
>> break;
>> }
>> case SMMU_CMD_CFGI_CD:
>> @@ -1470,8 +1491,8 @@ static int smmuv3_cmdq_consume(SMMUv3State *s,
>> Error **errp, SMMUSecSID sec_sid)
>> break;
>> }
>> - trace_smmuv3_cmdq_cfgi_cd(sid);
>> - smmuv3_flush_config(sdev);
>> + trace_smmuv3_cmdq_cfgi_cd(ssec, sid);
>> + smmuv3_flush_config(sdev, ssec);
>> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, sdev, errp)) {
>> cmd_error = SMMU_CERROR_ILL;
>> break;
>> @@ -1492,7 +1513,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s,
>> Error **errp, SMMUSecSID sec_sid)
>> * VMID is only matched when stage 2 is supported,
>> otherwise set it
>> * to -1 as the value used for stage-1 only VMIDs.
>> */
>> - if (STAGE2_SUPPORTED(s)) {
>> + if (queue_stage2_supported) {
>> vmid = CMD_VMID(&cmd);
>> }
>> @@ -1518,18 +1539,27 @@ static int smmuv3_cmdq_consume(SMMUv3State
>> *s, Error **errp, SMMUSecSID sec_sid)
>> * If stage-2 is supported, invalidate for this VMID
>> only, otherwise
>> * invalidate the whole thing.
>> */
>> - if (STAGE2_SUPPORTED(s)) {
>> + if (queue_stage2_supported) {
>> vmid = CMD_VMID(&cmd);
>> trace_smmuv3_cmdq_tlbi_nh(sec_sid, vmid);
>> smmu_iotlb_inv_vmid_s1(bs, vmid, sec_sid);
>> break;
>> }
>> - QEMU_FALLTHROUGH;
>> + trace_smmuv3_cmdq_tlbi_nh(sec_sid, vmid);
>> + smmu_inv_notifiers_all(&s->smmu_state);
>> + smmu_iotlb_inv_all(bs, sec_sid);
>> + break;
>> }
>> case SMMU_CMD_TLBI_NSNH_ALL:
>> trace_smmuv3_cmdq_tlbi_nsnh();
>> smmu_inv_notifiers_all(&s->smmu_state);
>> - smmu_iotlb_inv_all(bs);
>> + /*
>> + * According to (IHI 0070G.b) 4.4.4.1 CMD_TLBI_NSNH_ALL,
>> Page 194:
>> + * "When issuing to the Realm programming interface,
>> even though
>> + * this command has NS in its name, it only applies to
>> Realm entries."
>> + */
>> + smmu_iotlb_inv_all(bs, sec_sid > SMMU_SEC_SID_S ?
>> + sec_sid : SMMU_SEC_SID_NS);
>> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
>> cmd_error = SMMU_CERROR_ILL;
>> break;
>> @@ -1541,7 +1571,8 @@ static int smmuv3_cmdq_consume(SMMUv3State *s,
>> Error **errp, SMMUSecSID sec_sid)
>> cmd_error = SMMU_CERROR_ILL;
>> break;
>> }
>> - smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1,
>> SMMU_SEC_SID_NS);
>> + smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1, sec_sid,
>> + queue_stage2_supported);
>> if (!smmuv3_accel_issue_inv_cmd(s, &cmd, NULL, errp)) {
>> cmd_error = SMMU_CERROR_ILL;
>> break;
>> @@ -1570,7 +1601,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s,
>> Error **errp, SMMUSecSID sec_sid)
>> * As currently only either s1 or s2 are supported
>> * we can reuse same function for s2.
>> */
>> - smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2,
>> SMMU_SEC_SID_NS);
>> + smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2,
>> SMMU_SEC_SID_NS, true);
>> break;
>> case SMMU_CMD_ATC_INV:
>> {
>> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
>> index ca8485c96af..64f308a8d35 100644
>> --- a/hw/arm/trace-events
>> +++ b/hw/arm/trace-events
>> @@ -51,9 +51,9 @@ smmuv3_translate_success(const char *n, uint16_t
>> sid, uint64_t iova, uint64_t tr
>> smmuv3_get_cd(uint64_t addr) "CD addr: 0x%"PRIx64
>> smmuv3_decode_cd(uint32_t oas) "oas=%d"
>> smmuv3_decode_cd_tt(int i, uint32_t tsz, uint64_t ttb, uint32_t
>> granule_sz, bool had) "TT[%d]:tsz:%d ttb:0x%"PRIx64" granule_sz:%d
>> had:%d"
>> -smmuv3_cmdq_cfgi_ste(int streamid) "streamid= 0x%x"
>> -smmuv3_cmdq_cfgi_ste_range(int start, int end) "start=0x%x - end=0x%x"
>> -smmuv3_cmdq_cfgi_cd(uint32_t sid) "sid=0x%x"
>> +smmuv3_cmdq_cfgi_ste(int ssec, int streamid) "ssec=%d streamid= 0x%x"
>> +smmuv3_cmdq_cfgi_ste_range(int ssec, int start, int end) "ssec=%d
>> start=0x%x - end=0x%x"
>> +smmuv3_cmdq_cfgi_cd(int ssec, uint32_t sid) "ssec=%d sid=0x%x"
>> smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t
>> misses, uint32_t perc) "Config cache HIT for sid=0x%x (hits=%d,
>> misses=%d, hit rate=%d)"
>> smmuv3_config_cache_miss(uint32_t sid, uint32_t hits, uint32_t
>> misses, uint32_t perc) "Config cache MISS for sid=0x%x (hits=%d,
>> misses=%d, hit rate=%d)"
>> smmuv3_range_inval(int sec_sid, int vmid, int asid, uint64_t addr,
>> uint8_t tg, uint64_t num_pages, uint8_t ttl, bool leaf, int stage)
>> "sec_sid=%d vmid=%d asid=%d addr=0x%"PRIx64" tg=%d
>> num_pages=0x%"PRIx64" ttl=%d leaf=%d stage=%d"
>> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
>> index 7d1d0936921..d05cf6ae53b 100644
>> --- a/include/hw/arm/smmu-common.h
>> +++ b/include/hw/arm/smmu-common.h
>> @@ -259,7 +259,7 @@ void smmu_iotlb_insert(SMMUState *bs,
>> SMMUTransCfg *cfg, SMMUTLBEntry *entry);
>> SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
>> uint8_t tg, uint8_t level,
>> SMMUSecSID sec_sid);
>> SMMUConfigKey smmu_get_config_key(SMMUDevice *sdev, SMMUSecSID
>> sec_sid);
>> -void smmu_iotlb_inv_all(SMMUState *s);
>> +void smmu_iotlb_inv_all(SMMUState *s, SMMUSecSID sec_sid);
>> void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid,
>> SMMUSecSID sec_sid);
>> void smmu_iotlb_inv_vmid(SMMUState *s, int vmid, SMMUSecSID sec_sid);
>> @@ -270,8 +270,10 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid,
>> int vmid, dma_addr_t iova,
>> void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa,
>> uint8_t tg,
>> uint64_t num_pages, uint8_t ttl,
>> SMMUSecSID sec_sid);
>> -void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range);
>> -void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev);
>> +void smmu_configs_inv_sid_range(SMMUState *s, SMMUSIDRange sid_range,
>> + SMMUSecSID sec_sid);
>> +void smmu_configs_inv_sdev(SMMUState *s, SMMUDevice *sdev,
>> + SMMUSecSID sec_sid);
>> /* Unmap the range of all the notifiers registered to any IOMMU mr */
>> void smmu_inv_notifiers_all(SMMUState *s);
>
> Looks ok overall.
>
> Using SMMU_SEC_SID_NUM as a special value to trigger all
> flush/invalidate works, but it's a bit surprising to read to be honest.
>
> It could be more explicit to introduce the two next functions:
> smmu_iotlb_inv_by_sec_sid(SMMUState *s, SMMUSecSID sec_sid)
> smmuv3_flush_config_by_sec_sid(SMMUDevice *sdev, SMMUSecSID sec_sid)
>
> And in addition:
> smmu_iotlb_inv_all with the current semantic (invalidate all entries).
> Same for smmuv3_flush_config (flush all configs).
>
> What do you think about it?
Thank you for the review and the suggestion. I agree that using
SMMU_SEC_SID_NUM as a special value to trigger a full flush/invalidate
is not ideal in terms of readability.
I will adopt your approach and split the functions in the next version.
Best regards,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 21/31] hw/arm/smmuv3: Add access checks for GERROR_IRQ_CFG registers
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (19 preceding siblings ...)
2026-02-21 10:17 ` [RFC v4 20/31] hw/arm/smmu: Make CMDQ invalidation security-state aware Tao Tang
@ 2026-02-21 10:17 ` Tao Tang
2026-02-25 21:48 ` Pierrick Bouvier
2026-02-21 10:18 ` [RFC v4 22/31] hw/arm/smmuv3: Add access checks for STRTAB_BASE and CR2 registers Tao Tang
` (9 subsequent siblings)
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:17 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Add helper functions smmu_msi_supported() and smmu_gerror_irq_cfg_writable()
to check accessibility of GERROR_IRQ_CFG registers. Reading returns RES0
when MSI is not supported. Writing is ignored when GERROR_IRQEN is set.
Additionally, mask reserved bits on writes using SMMU_GERROR_IRQ_CFG0_RESERVED.
Fixes: fae4be38b35d ("hw/arm/smmuv3: Implement MMIO write operations")
Fixes: 10a83cb9887e ("hw/arm/smmuv3: Skeleton")
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 75 insertions(+), 1 deletion(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 29e862b8ae3..eb9c6658a12 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1369,6 +1369,28 @@ static inline bool smmu_cmdq_stage2_supported(SMMUv3State *s, SMMUSecSID sec_sid
return true;
}
+/* Check if MSI is supported */
+static inline bool smmu_msi_supported(SMMUv3State *s)
+{
+ return FIELD_EX32(s->bank[SMMU_SEC_SID_NS].idr[0], IDR0, MSI);
+}
+
+/* Check if secure GERROR_IRQ_CFGx registers are writable */
+static inline bool smmu_gerror_irq_cfg_writable(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ if (!smmu_msi_supported(s)) {
+ return false;
+ }
+
+ /*
+ * Only writable if:
+ * - IRQ_CTRL.GERROR_IRQEN == 0 and
+ * - IRQ_CTRLACK.GERROR_IRQEN == 0.
+ * IRQ_CTRL and IRQ_CTRL_ACK are folded into a single backing field here.
+ */
+ return (FIELD_EX32(s->bank[sec_sid].irq_ctrl, IRQ_CTRL, GERROR_IRQEN) == 0);
+}
+
static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
{
SMMUState *bs = ARM_SMMU(s);
@@ -1669,7 +1691,14 @@ static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
switch (offset) {
case A_GERROR_IRQ_CFG0:
- bank->gerror_irq_cfg0 = data;
+ if (!smmu_gerror_irq_cfg_writable(s, reg_sec_sid)) {
+ /* SMMU_(*_)_IRQ_CTRL.GERROR_IRQEN == 1: IGNORED this write */
+ qemu_log_mask(LOG_GUEST_ERROR, "GERROR_IRQ_CFG0 write ignored: "
+ "register is RO when IRQ enabled\n");
+ return MEMTX_OK;
+ }
+
+ bank->gerror_irq_cfg0 = data & SMMU_GERROR_IRQ_CFG0_RESERVED;
return MEMTX_OK;
case A_STRTAB_BASE:
bank->strtab_base = data;
@@ -1731,12 +1760,31 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
smmuv3_cmdq_consume(s, &local_err, reg_sec_sid);
break;
case A_GERROR_IRQ_CFG0: /* 64b */
+ if (!smmu_gerror_irq_cfg_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "GERROR_IRQ_CFG0 write ignored: "
+ "register is RO when IRQ enabled\n");
+ return MEMTX_OK;
+ }
+
+ data &= SMMU_GERROR_IRQ_CFG0_RESERVED;
bank->gerror_irq_cfg0 = deposit64(bank->gerror_irq_cfg0, 0, 32, data);
break;
case A_GERROR_IRQ_CFG0 + 4:
+ if (!smmu_gerror_irq_cfg_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "GERROR_IRQ_CFG0 + 4 write ignored: "
+ "register is RO when IRQ enabled\n");
+ return MEMTX_OK;
+ }
+
bank->gerror_irq_cfg0 = deposit64(bank->gerror_irq_cfg0, 32, 32, data);
break;
case A_GERROR_IRQ_CFG1:
+ if (!smmu_gerror_irq_cfg_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR, "GERROR_IRQ_CFG1 write ignored: "
+ "register is RO when IRQ enabled\n");
+ return MEMTX_OK;
+ }
+
bank->gerror_irq_cfg1 = data;
break;
case A_GERROR_IRQ_CFG2:
@@ -1858,6 +1906,12 @@ static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
switch (offset) {
case A_GERROR_IRQ_CFG0:
+ /* SMMU_(*_)GERROR_IRQ_CFG0 BOTH check SMMU_IDR0.MSI */
+ if (!smmu_msi_supported(s)) {
+ *data = 0; /* RES0 */
+ return MEMTX_OK;
+ }
+
*data = bank->gerror_irq_cfg0;
return MEMTX_OK;
case A_STRTAB_BASE:
@@ -1926,15 +1980,35 @@ static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
*data = bank->gerrorn;
return MEMTX_OK;
case A_GERROR_IRQ_CFG0: /* 64b */
+ if (!smmu_msi_supported(s)) {
+ *data = 0; /* RES0 */
+ return MEMTX_OK;
+ }
+
*data = extract64(bank->gerror_irq_cfg0, 0, 32);
return MEMTX_OK;
case A_GERROR_IRQ_CFG0 + 4:
+ if (!smmu_msi_supported(s)) {
+ *data = 0; /* RES0 */
+ return MEMTX_OK;
+ }
+
*data = extract64(bank->gerror_irq_cfg0, 32, 32);
return MEMTX_OK;
case A_GERROR_IRQ_CFG1:
+ if (!smmu_msi_supported(s)) {
+ *data = 0; /* RES0 */
+ return MEMTX_OK;
+ }
+
*data = bank->gerror_irq_cfg1;
return MEMTX_OK;
case A_GERROR_IRQ_CFG2:
+ if (!smmu_msi_supported(s)) {
+ *data = 0; /* RES0 */
+ return MEMTX_OK;
+ }
+
*data = bank->gerror_irq_cfg2;
return MEMTX_OK;
case A_STRTAB_BASE: /* 64b */
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 21/31] hw/arm/smmuv3: Add access checks for GERROR_IRQ_CFG registers
2026-02-21 10:17 ` [RFC v4 21/31] hw/arm/smmuv3: Add access checks for GERROR_IRQ_CFG registers Tao Tang
@ 2026-02-25 21:48 ` Pierrick Bouvier
0 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:48 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:17 AM, Tao Tang wrote:
> Add helper functions smmu_msi_supported() and smmu_gerror_irq_cfg_writable()
> to check accessibility of GERROR_IRQ_CFG registers. Reading returns RES0
> when MSI is not supported. Writing is ignored when GERROR_IRQEN is set.
>
> Additionally, mask reserved bits on writes using SMMU_GERROR_IRQ_CFG0_RESERVED.
>
> Fixes: fae4be38b35d ("hw/arm/smmuv3: Implement MMIO write operations")
> Fixes: 10a83cb9887e ("hw/arm/smmuv3: Skeleton")
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 75 insertions(+), 1 deletion(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 22/31] hw/arm/smmuv3: Add access checks for STRTAB_BASE and CR2 registers
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (20 preceding siblings ...)
2026-02-21 10:17 ` [RFC v4 21/31] hw/arm/smmuv3: Add access checks for GERROR_IRQ_CFG registers Tao Tang
@ 2026-02-21 10:18 ` Tao Tang
2026-02-25 21:53 ` Pierrick Bouvier
2026-02-21 10:18 ` [RFC v4 23/31] hw/arm/smmuv3: Add access checks for CMDQ and EVENTQ registers Tao Tang
` (8 subsequent siblings)
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:18 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Add access control for SMMU_STRTAB_BASE and SMMU_CR2 registers to
ensure they can only be modified when the SMMU is disabled.
This implements:
- smmuv3_smmu_disabled_stable(): Check whether the SMMU is in a stable
disabled state (CR0.SMMUEN == 0 and CR0ACK.SMMUEN == 0);
- smmu_strtab_base_writable(): returns true only when IDR1.TABLES_PRESET==0
and SMMU is completely disabled.
Additionally, mask reserved bits on writes to SMMU_STRTAB_BASE using
SMMU_STRTAB_BASE_RESERVED.
Fixes: fae4be38b35d ("hw/arm/smmuv3: Implement MMIO write operations")
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 67 insertions(+), 2 deletions(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index eb9c6658a12..163c07adce4 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1391,6 +1391,36 @@ static inline bool smmu_gerror_irq_cfg_writable(SMMUv3State *s, SMMUSecSID sec_s
return (FIELD_EX32(s->bank[sec_sid].irq_ctrl, IRQ_CTRL, GERROR_IRQEN) == 0);
}
+static inline int smmuv3_get_cr0ack_smmuen(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ /*
+ * CR0, CR0ACK, S_CR0 and S_CR0ACK are bit-layout compatible, so we reuse
+ * the CR0 field definitions and only switch banks via sec_sid to reduce
+ * code duplication. Also the other bits in CR0/CR0ACK are relevant here.
+ */
+ return FIELD_EX32(s->bank[sec_sid].cr0ack, CR0, SMMUEN);
+}
+
+/* Check if SMMU is disabled in stable status */
+static inline bool smmuv3_smmu_disabled_stable(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ int cr0_smmuen = smmu_enabled(s, sec_sid);
+ int cr0ack_smmuen = smmuv3_get_cr0ack_smmuen(s, sec_sid);
+ return (cr0_smmuen == 0 && cr0ack_smmuen == 0);
+}
+
+/* Check if STRTAB_BASE register is writable */
+static bool smmu_strtab_base_writable(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ /* Use NS bank as it's designed for all security states */
+ if (FIELD_EX32(s->bank[SMMU_SEC_SID_NS].idr[1], IDR1, TABLES_PRESET)) {
+ return false;
+ }
+
+ /* Check SMMUEN conditions for the specific security domain */
+ return smmuv3_smmu_disabled_stable(s, sec_sid);
+}
+
static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
{
SMMUState *bs = ARM_SMMU(s);
@@ -1701,7 +1731,14 @@ static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
bank->gerror_irq_cfg0 = data & SMMU_GERROR_IRQ_CFG0_RESERVED;
return MEMTX_OK;
case A_STRTAB_BASE:
- bank->strtab_base = data;
+ if (!smmu_strtab_base_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "STRTAB_BASE write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ /* Clear reserved bits according to spec */
+ bank->strtab_base = data & SMMU_STRTAB_BASE_RESERVED;
return MEMTX_OK;
case A_CMDQ_BASE:
bank->cmdq.base = data;
@@ -1746,7 +1783,15 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
bank->cr[1] = data;
break;
case A_CR2:
- bank->cr[2] = data;
+ if (smmuv3_smmu_disabled_stable(s, reg_sec_sid)) {
+ /* Allow write: SMMUEN is 0 in both CR0 and CR0ACK */
+ bank->cr[2] = data;
+ } else {
+ /* CONSTRAINED UNPREDICTABLE behavior: Ignore this write */
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CR2 write ignored: register is read-only when "
+ "CR0.SMMUEN or CR0ACK.SMMUEN is set\n");
+ }
break;
case A_IRQ_CTRL:
bank->irq_ctrl = data;
@@ -1802,12 +1847,32 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
}
break;
case A_STRTAB_BASE: /* 64b */
+ if (!smmu_strtab_base_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "STRTAB_BASE write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ data &= SMMU_STRTAB_BASE_RESERVED;
bank->strtab_base = deposit64(bank->strtab_base, 0, 32, data);
break;
case A_STRTAB_BASE + 4:
+ if (!smmu_strtab_base_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "STRTAB_BASE + 4 write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ data &= SMMU_STRTAB_BASE_RESERVED;
bank->strtab_base = deposit64(bank->strtab_base, 32, 32, data);
break;
case A_STRTAB_BASE_CFG:
+ if (!smmu_strtab_base_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "STRTAB_BASE_CFG write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
bank->strtab_base_cfg = data;
if (FIELD_EX32(data, STRTAB_BASE_CFG, FMT) == 1) {
bank->sid_split = FIELD_EX32(data, STRTAB_BASE_CFG, SPLIT);
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 22/31] hw/arm/smmuv3: Add access checks for STRTAB_BASE and CR2 registers
2026-02-21 10:18 ` [RFC v4 22/31] hw/arm/smmuv3: Add access checks for STRTAB_BASE and CR2 registers Tao Tang
@ 2026-02-25 21:53 ` Pierrick Bouvier
0 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:53 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:18 AM, Tao Tang wrote:
> Add access control for SMMU_STRTAB_BASE and SMMU_CR2 registers to
> ensure they can only be modified when the SMMU is disabled.
>
> This implements:
> - smmuv3_smmu_disabled_stable(): Check whether the SMMU is in a stable
> disabled state (CR0.SMMUEN == 0 and CR0ACK.SMMUEN == 0);
> - smmu_strtab_base_writable(): returns true only when IDR1.TABLES_PRESET==0
> and SMMU is completely disabled.
>
> Additionally, mask reserved bits on writes to SMMU_STRTAB_BASE using
> SMMU_STRTAB_BASE_RESERVED.
>
> Fixes: fae4be38b35d ("hw/arm/smmuv3: Implement MMIO write operations")
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++--
> 1 file changed, 67 insertions(+), 2 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 23/31] hw/arm/smmuv3: Add access checks for CMDQ and EVENTQ registers
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (21 preceding siblings ...)
2026-02-21 10:18 ` [RFC v4 22/31] hw/arm/smmuv3: Add access checks for STRTAB_BASE and CR2 registers Tao Tang
@ 2026-02-21 10:18 ` Tao Tang
2026-02-25 21:59 ` Pierrick Bouvier
2026-02-21 10:18 ` [RFC v4 24/31] hw/arm/smmuv3: Determine register bank from MMIO offset Tao Tang
` (7 subsequent siblings)
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:18 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Add access control for command queue and event queue related registers
to ensure they can only be modified under proper conditions.
For command queue (CMDQ):
- smmu_cmdq_disabled_stable(): checks CMDQ bit in CR0/CR0ACK
- smmu_cmdq_base_writable(): checks IDR1.QUEUES_PRESET==0 and CMDQ disabled
For event queue (EVTQ):
- smmu_eventq_disabled_stable(): checks EVTQ bit in CR0/CR0ACK
- smmu_eventq_base_writable():checks IDR1.QUEUES_PRESET==0 and EVTQ disabled
- smmu_eventq_irq_cfg_writable(): checks MSI support and EVENTQ_IRQEN state
Additionally, mask reserved bits on writes using SMMU_QUEUE_BASE_RESERVED
for queue base registers and SMMU_EVENTQ_IRQ_CFG0_RESERVED for
EVENTQ_IRQ_CFG0.
Fixes: fae4be38b35d ("hw/arm/smmuv3: Implement MMIO write operations")
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 154 insertions(+), 3 deletions(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 163c07adce4..9c09ea0716e 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1421,6 +1421,73 @@ static bool smmu_strtab_base_writable(SMMUv3State *s, SMMUSecSID sec_sid)
return smmuv3_smmu_disabled_stable(s, sec_sid);
}
+static inline int smmuv3_get_cr0_cmdqen(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ return FIELD_EX32(s->bank[sec_sid].cr[0], CR0, CMDQEN);
+}
+
+static inline int smmuv3_get_cr0ack_cmdqen(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ return FIELD_EX32(s->bank[sec_sid].cr0ack, CR0, CMDQEN);
+}
+
+static inline int smmuv3_get_cr0_eventqen(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ return FIELD_EX32(s->bank[sec_sid].cr[0], CR0, EVENTQEN);
+}
+
+static inline int smmuv3_get_cr0ack_eventqen(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ return FIELD_EX32(s->bank[sec_sid].cr0ack, CR0, EVENTQEN);
+}
+
+/* Check if CMDQ is disabled in stable status */
+static bool smmu_cmdq_disabled_stable(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ int cr0_cmdqen = smmuv3_get_cr0_cmdqen(s, sec_sid);
+ int cr0ack_cmdqen = smmuv3_get_cr0ack_cmdqen(s, sec_sid);
+ return (cr0_cmdqen == 0 && cr0ack_cmdqen == 0);
+}
+
+/* Check if CMDQ_BASE register is writable */
+static bool smmu_cmdq_base_writable(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ /* Use NS bank as it's designed for all security states */
+ if (FIELD_EX32(s->bank[SMMU_SEC_SID_NS].idr[1], IDR1, QUEUES_PRESET)) {
+ return false;
+ }
+
+ return smmu_cmdq_disabled_stable(s, sec_sid);
+}
+
+/* Check if EVENTQ is disabled in stable status */
+static bool smmu_eventq_disabled_stable(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ int cr0_eventqen = smmuv3_get_cr0_eventqen(s, sec_sid);
+ int cr0ack_eventqen = smmuv3_get_cr0ack_eventqen(s, sec_sid);
+ return (cr0_eventqen == 0 && cr0ack_eventqen == 0);
+}
+
+/* Check if EVENTQ_BASE register is writable */
+static bool smmu_eventq_base_writable(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ if (FIELD_EX32(s->bank[SMMU_SEC_SID_NS].idr[1], IDR1, QUEUES_PRESET)) {
+ return false;
+ }
+
+ return smmu_eventq_disabled_stable(s, sec_sid);
+}
+
+/* Check if EVENTQ_IRQ_CFGx is writable */
+static bool smmu_eventq_irq_cfg_writable(SMMUv3State *s, SMMUSecSID sec_sid)
+{
+ if (!smmu_msi_supported(s)) {
+ return false;
+ }
+
+ return (FIELD_EX32(s->bank[sec_sid].irq_ctrl, IRQ_CTRL, EVENTQ_IRQEN) == 0);
+}
+
static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
{
SMMUState *bs = ARM_SMMU(s);
@@ -1741,21 +1808,39 @@ static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
bank->strtab_base = data & SMMU_STRTAB_BASE_RESERVED;
return MEMTX_OK;
case A_CMDQ_BASE:
- bank->cmdq.base = data;
+ if (!smmu_cmdq_base_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CMDQ_BASE write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ bank->cmdq.base = data & SMMU_QUEUE_BASE_RESERVED;
bank->cmdq.log2size = extract64(bank->cmdq.base, 0, 5);
if (bank->cmdq.log2size > SMMU_CMDQS) {
bank->cmdq.log2size = SMMU_CMDQS;
}
return MEMTX_OK;
case A_EVENTQ_BASE:
- bank->eventq.base = data;
+ if (!smmu_eventq_base_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "EVENTQ_BASE write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ bank->eventq.base = data & SMMU_QUEUE_BASE_RESERVED;
bank->eventq.log2size = extract64(bank->eventq.base, 0, 5);
if (bank->eventq.log2size > SMMU_EVENTQS) {
bank->eventq.log2size = SMMU_EVENTQS;
}
return MEMTX_OK;
case A_EVENTQ_IRQ_CFG0:
- bank->eventq_irq_cfg0 = data;
+ if (!smmu_eventq_irq_cfg_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "EVENTQ_IRQ_CFG0 write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ bank->eventq_irq_cfg0 = data & SMMU_EVENTQ_IRQ_CFG0_RESERVED;
return MEMTX_OK;
default:
qemu_log_mask(LOG_UNIMP,
@@ -1880,6 +1965,13 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
}
break;
case A_CMDQ_BASE: /* 64b */
+ if (!smmu_cmdq_base_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CMDQ_BASE write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ data &= SMMU_QUEUE_BASE_RESERVED;
bank->cmdq.base = deposit64(bank->cmdq.base, 0, 32, data);
bank->cmdq.log2size = extract64(bank->cmdq.base, 0, 5);
if (bank->cmdq.log2size > SMMU_CMDQS) {
@@ -1887,6 +1979,13 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
}
break;
case A_CMDQ_BASE + 4: /* 64b */
+ if (!smmu_cmdq_base_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CMDQ_BASE + 4 write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ data &= SMMU_QUEUE_BASE_RESERVED;
bank->cmdq.base = deposit64(bank->cmdq.base, 32, 32, data);
break;
case A_CMDQ_PROD:
@@ -1894,9 +1993,22 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
smmuv3_cmdq_consume(s, &local_err, reg_sec_sid);
break;
case A_CMDQ_CONS:
+ if (!smmu_cmdq_disabled_stable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "CMDQ_CONS write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
bank->cmdq.cons = data;
break;
case A_EVENTQ_BASE: /* 64b */
+ if (!smmu_eventq_base_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "EVENTQ_BASE write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ data &= SMMU_QUEUE_BASE_RESERVED;
bank->eventq.base = deposit64(bank->eventq.base, 0, 32, data);
bank->eventq.log2size = extract64(bank->eventq.base, 0, 5);
if (bank->eventq.log2size > SMMU_EVENTQS) {
@@ -1904,24 +2016,63 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
}
break;
case A_EVENTQ_BASE + 4:
+ if (!smmu_eventq_base_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "EVENTQ_BASE + 4 write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ data &= SMMU_QUEUE_BASE_RESERVED;
bank->eventq.base = deposit64(bank->eventq.base, 32, 32, data);
break;
case A_EVENTQ_PROD:
+ if (!smmu_eventq_disabled_stable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "EVENTQ_PROD write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
bank->eventq.prod = data;
break;
case A_EVENTQ_CONS:
bank->eventq.cons = data;
break;
case A_EVENTQ_IRQ_CFG0: /* 64b */
+ if (!smmu_eventq_irq_cfg_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "EVENTQ_IRQ_CFG0 write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ data &= SMMU_EVENTQ_IRQ_CFG0_RESERVED;
bank->eventq_irq_cfg0 = deposit64(bank->eventq_irq_cfg0, 0, 32, data);
break;
case A_EVENTQ_IRQ_CFG0 + 4:
+ if (!smmu_eventq_irq_cfg_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "EVENTQ_IRQ_CFG0+4 write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
+ data &= SMMU_EVENTQ_IRQ_CFG0_RESERVED;
bank->eventq_irq_cfg0 = deposit64(bank->eventq_irq_cfg0, 32, 32, data);
break;
case A_EVENTQ_IRQ_CFG1:
+ if (!smmu_eventq_irq_cfg_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "EVENTQ_IRQ_CFG1 write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
bank->eventq_irq_cfg1 = data;
break;
case A_EVENTQ_IRQ_CFG2:
+ if (!smmu_eventq_irq_cfg_writable(s, reg_sec_sid)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "EVENTQ_IRQ_CFG2 write ignored: register is RO\n");
+ return MEMTX_OK;
+ }
+
bank->eventq_irq_cfg2 = data;
break;
default:
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 23/31] hw/arm/smmuv3: Add access checks for CMDQ and EVENTQ registers
2026-02-21 10:18 ` [RFC v4 23/31] hw/arm/smmuv3: Add access checks for CMDQ and EVENTQ registers Tao Tang
@ 2026-02-25 21:59 ` Pierrick Bouvier
2026-02-27 15:44 ` Tao Tang
0 siblings, 1 reply; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:59 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:18 AM, Tao Tang wrote:
> Add access control for command queue and event queue related registers
> to ensure they can only be modified under proper conditions.
>
> For command queue (CMDQ):
> - smmu_cmdq_disabled_stable(): checks CMDQ bit in CR0/CR0ACK
> - smmu_cmdq_base_writable(): checks IDR1.QUEUES_PRESET==0 and CMDQ disabled
>
> For event queue (EVTQ):
> - smmu_eventq_disabled_stable(): checks EVTQ bit in CR0/CR0ACK
> - smmu_eventq_base_writable():checks IDR1.QUEUES_PRESET==0 and EVTQ disabled
> - smmu_eventq_irq_cfg_writable(): checks MSI support and EVENTQ_IRQEN state
>
> Additionally, mask reserved bits on writes using SMMU_QUEUE_BASE_RESERVED
> for queue base registers and SMMU_EVENTQ_IRQ_CFG0_RESERVED for
> EVENTQ_IRQ_CFG0.
>
> Fixes: fae4be38b35d ("hw/arm/smmuv3: Implement MMIO write operations")
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 154 insertions(+), 3 deletions(-)
>
It seems like we use the same pattern a lot of time for various SMMU
registers, and makes me wonder if we could not introduce proper register
definitions with callbacks similar to Arm *_reginfo.
That said, it's definitely out of the scope for this series:
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 23/31] hw/arm/smmuv3: Add access checks for CMDQ and EVENTQ registers
2026-02-25 21:59 ` Pierrick Bouvier
@ 2026-02-27 15:44 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-27 15:44 UTC (permalink / raw)
To: Pierrick Bouvier, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
Hi Pierrick,
On 2026/2/26 05:59, Pierrick Bouvier wrote:
> On 2/21/26 2:18 AM, Tao Tang wrote:
>> Add access control for command queue and event queue related registers
>> to ensure they can only be modified under proper conditions.
>>
>> For command queue (CMDQ):
>> - smmu_cmdq_disabled_stable(): checks CMDQ bit in CR0/CR0ACK
>> - smmu_cmdq_base_writable(): checks IDR1.QUEUES_PRESET==0 and CMDQ
>> disabled
>>
>> For event queue (EVTQ):
>> - smmu_eventq_disabled_stable(): checks EVTQ bit in CR0/CR0ACK
>> - smmu_eventq_base_writable():checks IDR1.QUEUES_PRESET==0 and EVTQ
>> disabled
>> - smmu_eventq_irq_cfg_writable(): checks MSI support and EVENTQ_IRQEN
>> state
>>
>> Additionally, mask reserved bits on writes using
>> SMMU_QUEUE_BASE_RESERVED
>> for queue base registers and SMMU_EVENTQ_IRQ_CFG0_RESERVED for
>> EVENTQ_IRQ_CFG0.
>>
>> Fixes: fae4be38b35d ("hw/arm/smmuv3: Implement MMIO write operations")
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmuv3.c | 157 +++++++++++++++++++++++++++++++++++++++++++++++-
>> 1 file changed, 154 insertions(+), 3 deletions(-)
>>
>
> It seems like we use the same pattern a lot of time for various SMMU
> registers, and makes me wonder if we could not introduce proper
> register definitions with callbacks similar to Arm *_reginfo.
>
> That said, it's definitely out of the scope for this series:
> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Thanks for your suggestion. I will consider refactoring it after merging
the current series.
Best regards,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 24/31] hw/arm/smmuv3: Determine register bank from MMIO offset
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (22 preceding siblings ...)
2026-02-21 10:18 ` [RFC v4 23/31] hw/arm/smmuv3: Add access checks for CMDQ and EVENTQ registers Tao Tang
@ 2026-02-21 10:18 ` Tao Tang
2026-02-25 22:00 ` Pierrick Bouvier
2026-02-27 14:59 ` Mostafa Saleh
2026-02-21 10:18 ` [RFC v4 25/31] hw/arm/smmuv3: Implement SMMU_S_INIT register Tao Tang
` (6 subsequent siblings)
30 siblings, 2 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:18 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Modify the main MMIO handlers (smmu_write_mmio, smmu_read_mmio)
to determine the security state of the target register based on its
memory-mapped offset.
By checking if the offset is within the secure register space (>=
SMMU_SECURE_REG_START), the handlers can deduce the register's
SEC_SID (reg_sec_sid). This SID is then passed down to the register
access helper functions (smmu_writel, smmu_readl, etc.).
Inside these helpers, the switch statement now operates on a masked,
relative offset:
uint32_t reg_offset = offset & 0xfff;
switch (reg_offset) {
...
}
This design leverages a key feature of the SMMU specification: registers
with the same function across different 3 security states
(Non-secure, Secure, Realm) share the same relative offset. This avoids
significant code duplication. The reg_sec_sid passed from the MMIO
handler determines which security bank to operate on, while the masked
offset identifies the specific register within that bank.
It is important to distinguish between the security state of the
register itself and the security state of the access. A
higher-privilege security state is permitted to access registers
belonging to a lower-privilege state, but the reverse is not allowed.
This patch lays the groundwork for enforcing such rules.
For future compatibility with Realm states, the logic in the
else block corresponding to the secure offset check:
if (offset >= SMMU_SECURE_REG_START) {
reg_sec_sid = SMMU_SEC_SID_S;
} else {
/* Future Realm handling */
}
will need to be expanded.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 57 +++++++++++++++++++++++++++++++++----------------
1 file changed, 39 insertions(+), 18 deletions(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 9c09ea0716e..d81485a6a46 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1781,12 +1781,13 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
}
static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
- uint64_t data, MemTxAttrs attrs)
+ uint64_t data, MemTxAttrs attrs,
+ SMMUSecSID reg_sec_sid)
{
- SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
+ uint32_t reg_offset = offset & 0xfff;
- switch (offset) {
+ switch (reg_offset) {
case A_GERROR_IRQ_CFG0:
if (!smmu_gerror_irq_cfg_writable(s, reg_sec_sid)) {
/* SMMU_(*_)_IRQ_CTRL.GERROR_IRQEN == 1: IGNORED this write */
@@ -1851,13 +1852,14 @@ static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
}
static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
- uint64_t data, MemTxAttrs attrs)
+ uint64_t data, MemTxAttrs attrs,
+ SMMUSecSID reg_sec_sid)
{
Error *local_err = NULL;
- SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
+ uint32_t reg_offset = offset & 0xfff;
- switch (offset) {
+ switch (reg_offset) {
case A_CR0:
bank->cr[0] = data;
bank->cr0ack = data & ~SMMU_CR0_RESERVED;
@@ -2094,16 +2096,25 @@ static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t data,
SMMUState *sys = opaque;
SMMUv3State *s = ARM_SMMUV3(sys);
MemTxResult r;
+ SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
/* CONSTRAINED UNPREDICTABLE choice to have page0/1 be exact aliases */
offset &= ~0x10000;
+ /*
+ * Realm and Non-secure share the same page-local offset layout; Secure uses
+ * the same layout but is mapped starting at 0x8000(SMMU_SECURE_REG_START)
+ */
+ if (offset >= SMMU_SECURE_REG_START) {
+ reg_sec_sid = SMMU_SEC_SID_S;
+ }
+
switch (size) {
case 8:
- r = smmu_writell(s, offset, data, attrs);
+ r = smmu_writell(s, offset, data, attrs, reg_sec_sid);
break;
case 4:
- r = smmu_writel(s, offset, data, attrs);
+ r = smmu_writel(s, offset, data, attrs, reg_sec_sid);
break;
default:
r = MEMTX_ERROR;
@@ -2115,12 +2126,13 @@ static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t data,
}
static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
- uint64_t *data, MemTxAttrs attrs)
+ uint64_t *data, MemTxAttrs attrs,
+ SMMUSecSID reg_sec_sid)
{
- SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
+ uint32_t reg_offset = offset & 0xfff;
- switch (offset) {
+ switch (reg_offset) {
case A_GERROR_IRQ_CFG0:
/* SMMU_(*_)GERROR_IRQ_CFG0 BOTH check SMMU_IDR0.MSI */
if (!smmu_msi_supported(s)) {
@@ -2149,17 +2161,22 @@ static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
}
static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
- uint64_t *data, MemTxAttrs attrs)
+ uint64_t *data, MemTxAttrs attrs,
+ SMMUSecSID reg_sec_sid)
{
- SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
+ uint32_t reg_offset = offset & 0xfff;
- switch (offset) {
+ switch (reg_offset) {
case A_IDREGS ... A_IDREGS + 0x2f:
- *data = smmuv3_idreg(offset - A_IDREGS);
+ *data = smmuv3_idreg(reg_offset - A_IDREGS);
return MEMTX_OK;
case A_IDR0 ... A_IDR5:
- *data = bank->idr[(offset - A_IDR0) / 4];
+ if (reg_sec_sid == SMMU_SEC_SID_S) {
+ g_assert((reg_offset - A_IDR0) / 4 < 5);
+ }
+
+ *data = bank->idr[(reg_offset - A_IDR0) / 4];
return MEMTX_OK;
case A_IIDR:
*data = s->iidr;
@@ -2275,16 +2292,20 @@ static MemTxResult smmu_read_mmio(void *opaque, hwaddr offset, uint64_t *data,
SMMUState *sys = opaque;
SMMUv3State *s = ARM_SMMUV3(sys);
MemTxResult r;
+ SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
/* CONSTRAINED UNPREDICTABLE choice to have page0/1 be exact aliases */
offset &= ~0x10000;
+ if (offset >= SMMU_SECURE_REG_START) {
+ reg_sec_sid = SMMU_SEC_SID_S;
+ }
switch (size) {
case 8:
- r = smmu_readll(s, offset, data, attrs);
+ r = smmu_readll(s, offset, data, attrs, reg_sec_sid);
break;
case 4:
- r = smmu_readl(s, offset, data, attrs);
+ r = smmu_readl(s, offset, data, attrs, reg_sec_sid);
break;
default:
r = MEMTX_ERROR;
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 24/31] hw/arm/smmuv3: Determine register bank from MMIO offset
2026-02-21 10:18 ` [RFC v4 24/31] hw/arm/smmuv3: Determine register bank from MMIO offset Tao Tang
@ 2026-02-25 22:00 ` Pierrick Bouvier
2026-02-27 14:59 ` Mostafa Saleh
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 22:00 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:18 AM, Tao Tang wrote:
> Modify the main MMIO handlers (smmu_write_mmio, smmu_read_mmio)
> to determine the security state of the target register based on its
> memory-mapped offset.
>
> By checking if the offset is within the secure register space (>=
> SMMU_SECURE_REG_START), the handlers can deduce the register's
> SEC_SID (reg_sec_sid). This SID is then passed down to the register
> access helper functions (smmu_writel, smmu_readl, etc.).
>
> Inside these helpers, the switch statement now operates on a masked,
> relative offset:
>
> uint32_t reg_offset = offset & 0xfff;
> switch (reg_offset) {
> ...
> }
>
> This design leverages a key feature of the SMMU specification: registers
> with the same function across different 3 security states
> (Non-secure, Secure, Realm) share the same relative offset. This avoids
> significant code duplication. The reg_sec_sid passed from the MMIO
> handler determines which security bank to operate on, while the masked
> offset identifies the specific register within that bank.
>
> It is important to distinguish between the security state of the
> register itself and the security state of the access. A
> higher-privilege security state is permitted to access registers
> belonging to a lower-privilege state, but the reverse is not allowed.
> This patch lays the groundwork for enforcing such rules.
>
> For future compatibility with Realm states, the logic in the
> else block corresponding to the secure offset check:
>
> if (offset >= SMMU_SECURE_REG_START) {
> reg_sec_sid = SMMU_SEC_SID_S;
> } else {
> /* Future Realm handling */
> }
>
> will need to be expanded.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 57 +++++++++++++++++++++++++++++++++----------------
> 1 file changed, 39 insertions(+), 18 deletions(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 24/31] hw/arm/smmuv3: Determine register bank from MMIO offset
2026-02-21 10:18 ` [RFC v4 24/31] hw/arm/smmuv3: Determine register bank from MMIO offset Tao Tang
2026-02-25 22:00 ` Pierrick Bouvier
@ 2026-02-27 14:59 ` Mostafa Saleh
2026-03-01 16:24 ` Tao Tang
1 sibling, 1 reply; 136+ messages in thread
From: Mostafa Saleh @ 2026-02-27 14:59 UTC (permalink / raw)
To: Tao Tang
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
On Sat, Feb 21, 2026 at 06:18:29PM +0800, Tao Tang wrote:
> Modify the main MMIO handlers (smmu_write_mmio, smmu_read_mmio)
> to determine the security state of the target register based on its
> memory-mapped offset.
>
> By checking if the offset is within the secure register space (>=
> SMMU_SECURE_REG_START), the handlers can deduce the register's
> SEC_SID (reg_sec_sid). This SID is then passed down to the register
> access helper functions (smmu_writel, smmu_readl, etc.).
>
> Inside these helpers, the switch statement now operates on a masked,
> relative offset:
>
> uint32_t reg_offset = offset & 0xfff;
> switch (reg_offset) {
> ...
> }
>
> This design leverages a key feature of the SMMU specification: registers
> with the same function across different 3 security states
> (Non-secure, Secure, Realm) share the same relative offset. This avoids
> significant code duplication. The reg_sec_sid passed from the MMIO
> handler determines which security bank to operate on, while the masked
> offset identifies the specific register within that bank.
>
> It is important to distinguish between the security state of the
> register itself and the security state of the access. A
> higher-privilege security state is permitted to access registers
> belonging to a lower-privilege state, but the reverse is not allowed.
> This patch lays the groundwork for enforcing such rules.
>
> For future compatibility with Realm states, the logic in the
> else block corresponding to the secure offset check:
>
> if (offset >= SMMU_SECURE_REG_START) {
> reg_sec_sid = SMMU_SEC_SID_S;
> } else {
> /* Future Realm handling */
> }
>
> will need to be expanded.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 57 +++++++++++++++++++++++++++++++++----------------
> 1 file changed, 39 insertions(+), 18 deletions(-)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 9c09ea0716e..d81485a6a46 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1781,12 +1781,13 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> }
>
> static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
> - uint64_t data, MemTxAttrs attrs)
> + uint64_t data, MemTxAttrs attrs,
> + SMMUSecSID reg_sec_sid)
> {
> - SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
> SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
> + uint32_t reg_offset = offset & 0xfff;
This breaks all registers above 4k?
For example, TCU registers/PMU reside on some of this area and if SW
writes to those this might be aliased to something as CR0, which might
disable the SMMU and bypass some security checks. (in case it’s managed
by the hypervisor).
I believe you should check the secure offset explicitly to distinguish secure
and non-secure.
>
> - switch (offset) {
> + switch (reg_offset) {
> case A_GERROR_IRQ_CFG0:
> if (!smmu_gerror_irq_cfg_writable(s, reg_sec_sid)) {
> /* SMMU_(*_)_IRQ_CTRL.GERROR_IRQEN == 1: IGNORED this write */
> @@ -1851,13 +1852,14 @@ static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
> }
>
> static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
> - uint64_t data, MemTxAttrs attrs)
> + uint64_t data, MemTxAttrs attrs,
> + SMMUSecSID reg_sec_sid)
> {
> Error *local_err = NULL;
> - SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
> SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
> + uint32_t reg_offset = offset & 0xfff;
>
> - switch (offset) {
> + switch (reg_offset) {
> case A_CR0:
> bank->cr[0] = data;
> bank->cr0ack = data & ~SMMU_CR0_RESERVED;
> @@ -2094,16 +2096,25 @@ static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t data,
> SMMUState *sys = opaque;
> SMMUv3State *s = ARM_SMMUV3(sys);
> MemTxResult r;
> + SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
>
> /* CONSTRAINED UNPREDICTABLE choice to have page0/1 be exact aliases */
> offset &= ~0x10000;
>
> + /*
> + * Realm and Non-secure share the same page-local offset layout; Secure uses
> + * the same layout but is mapped starting at 0x8000(SMMU_SECURE_REG_START)
> + */
> + if (offset >= SMMU_SECURE_REG_START) {
> + reg_sec_sid = SMMU_SEC_SID_S;
> + }
> +
> switch (size) {
> case 8:
> - r = smmu_writell(s, offset, data, attrs);
> + r = smmu_writell(s, offset, data, attrs, reg_sec_sid);
> break;
> case 4:
> - r = smmu_writel(s, offset, data, attrs);
> + r = smmu_writel(s, offset, data, attrs, reg_sec_sid);
> break;
> default:
> r = MEMTX_ERROR;
> @@ -2115,12 +2126,13 @@ static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t data,
> }
>
> static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
> - uint64_t *data, MemTxAttrs attrs)
> + uint64_t *data, MemTxAttrs attrs,
> + SMMUSecSID reg_sec_sid)
> {
> - SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
> SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
> + uint32_t reg_offset = offset & 0xfff;
>
> - switch (offset) {
> + switch (reg_offset) {
> case A_GERROR_IRQ_CFG0:
> /* SMMU_(*_)GERROR_IRQ_CFG0 BOTH check SMMU_IDR0.MSI */
> if (!smmu_msi_supported(s)) {
> @@ -2149,17 +2161,22 @@ static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
> }
>
> static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
> - uint64_t *data, MemTxAttrs attrs)
> + uint64_t *data, MemTxAttrs attrs,
> + SMMUSecSID reg_sec_sid)
> {
> - SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
> SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
> + uint32_t reg_offset = offset & 0xfff;
>
> - switch (offset) {
> + switch (reg_offset) {
> case A_IDREGS ... A_IDREGS + 0x2f:
> - *data = smmuv3_idreg(offset - A_IDREGS);
> + *data = smmuv3_idreg(reg_offset - A_IDREGS);
> return MEMTX_OK;
> case A_IDR0 ... A_IDR5:
> - *data = bank->idr[(offset - A_IDR0) / 4];
> + if (reg_sec_sid == SMMU_SEC_SID_S) {
> + g_assert((reg_offset - A_IDR0) / 4 < 5);
Asserting here is too much as this can be easily triggered by guests,
we should follow the convention of other unimplemented registers.
Thanks,
Mostafa
> + }
> +
> + *data = bank->idr[(reg_offset - A_IDR0) / 4];
> return MEMTX_OK;
> case A_IIDR:
> *data = s->iidr;
> @@ -2275,16 +2292,20 @@ static MemTxResult smmu_read_mmio(void *opaque, hwaddr offset, uint64_t *data,
> SMMUState *sys = opaque;
> SMMUv3State *s = ARM_SMMUV3(sys);
> MemTxResult r;
> + SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
>
> /* CONSTRAINED UNPREDICTABLE choice to have page0/1 be exact aliases */
> offset &= ~0x10000;
> + if (offset >= SMMU_SECURE_REG_START) {
> + reg_sec_sid = SMMU_SEC_SID_S;
> + }
>
> switch (size) {
> case 8:
> - r = smmu_readll(s, offset, data, attrs);
> + r = smmu_readll(s, offset, data, attrs, reg_sec_sid);
> break;
> case 4:
> - r = smmu_readl(s, offset, data, attrs);
> + r = smmu_readl(s, offset, data, attrs, reg_sec_sid);
> break;
> default:
> r = MEMTX_ERROR;
> --
> 2.34.1
>
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 24/31] hw/arm/smmuv3: Determine register bank from MMIO offset
2026-02-27 14:59 ` Mostafa Saleh
@ 2026-03-01 16:24 ` Tao Tang
0 siblings, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-03-01 16:24 UTC (permalink / raw)
To: Mostafa Saleh
Cc: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum,
qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Chao Liu
Hi Mostafa,
On 2026/2/27 PM10:59, Mostafa Saleh wrote:
> On Sat, Feb 21, 2026 at 06:18:29PM +0800, Tao Tang wrote:
>> Modify the main MMIO handlers (smmu_write_mmio, smmu_read_mmio)
>> to determine the security state of the target register based on its
>> memory-mapped offset.
>>
>> By checking if the offset is within the secure register space (>=
>> SMMU_SECURE_REG_START), the handlers can deduce the register's
>> SEC_SID (reg_sec_sid). This SID is then passed down to the register
>> access helper functions (smmu_writel, smmu_readl, etc.).
>>
>> Inside these helpers, the switch statement now operates on a masked,
>> relative offset:
>>
>> uint32_t reg_offset = offset & 0xfff;
>> switch (reg_offset) {
>> ...
>> }
>>
>> This design leverages a key feature of the SMMU specification: registers
>> with the same function across different 3 security states
>> (Non-secure, Secure, Realm) share the same relative offset. This avoids
>> significant code duplication. The reg_sec_sid passed from the MMIO
>> handler determines which security bank to operate on, while the masked
>> offset identifies the specific register within that bank.
>>
>> It is important to distinguish between the security state of the
>> register itself and the security state of the access. A
>> higher-privilege security state is permitted to access registers
>> belonging to a lower-privilege state, but the reverse is not allowed.
>> This patch lays the groundwork for enforcing such rules.
>>
>> For future compatibility with Realm states, the logic in the
>> else block corresponding to the secure offset check:
>>
>> if (offset >= SMMU_SECURE_REG_START) {
>> reg_sec_sid = SMMU_SEC_SID_S;
>> } else {
>> /* Future Realm handling */
>> }
>>
>> will need to be expanded.
>>
>> Signed-off-by: Tao Tang<tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmuv3.c | 57 +++++++++++++++++++++++++++++++++----------------
>> 1 file changed, 39 insertions(+), 18 deletions(-)
>>
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index 9c09ea0716e..d81485a6a46 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -1781,12 +1781,13 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
>> }
>>
>> static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
>> - uint64_t data, MemTxAttrs attrs)
>> + uint64_t data, MemTxAttrs attrs,
>> + SMMUSecSID reg_sec_sid)
>> {
>> - SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
>> SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
>> + uint32_t reg_offset = offset & 0xfff;
> This breaks all registers above 4k?
> For example, TCU registers/PMU reside on some of this area and if SW
> writes to those this might be aliased to something as CR0, which might
> disable the SMMU and bypass some security checks. (in case it’s managed
> by the hypervisor).
>
> I believe you should check the secure offset explicitly to distinguish secure
> and non-secure.
Thanks for catching this. You’re right! I implicitly assumed that
anything “above 4KB” in the register aperture could be safely decoded by
masking to a 4KB-local offset, but that overlooks the fact that real
SMMU IPs populate the *IMPLEMENTATION DEFINED* windows with meaningful
blocks. In practice, these implementation-defined ranges appear to start
around 0x0E00 in the main bank and 0x8E00 in the secure bank (per the
register overview)? So collapsing offsets with offset & 0xfff can
easily alias accesses from those regions onto architected registers.
I’ll rework this part: explicitly decode the MMIO access by **register
region/window**, and only canonicalize offsets in a way that preserves
at least the 64KB page granularity.
>>
>> - switch (offset) {
>> + switch (reg_offset) {
>> case A_GERROR_IRQ_CFG0:
>> if (!smmu_gerror_irq_cfg_writable(s, reg_sec_sid)) {
>> /* SMMU_(*_)_IRQ_CTRL.GERROR_IRQEN == 1: IGNORED this write */
>> @@ -1851,13 +1852,14 @@ static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
>> }
>>
>> static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
>> - uint64_t data, MemTxAttrs attrs)
>> + uint64_t data, MemTxAttrs attrs,
>> + SMMUSecSID reg_sec_sid)
>> {
>> Error *local_err = NULL;
>> - SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
>> SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
>> + uint32_t reg_offset = offset & 0xfff;
>>
>> - switch (offset) {
>> + switch (reg_offset) {
>> case A_CR0:
>> bank->cr[0] = data;
>> bank->cr0ack = data & ~SMMU_CR0_RESERVED;
>> @@ -2094,16 +2096,25 @@ static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t data,
>> SMMUState *sys = opaque;
>> SMMUv3State *s = ARM_SMMUV3(sys);
>> MemTxResult r;
>> + SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
>>
>> /* CONSTRAINED UNPREDICTABLE choice to have page0/1 be exact aliases */
>> offset &= ~0x10000;
>>
>> + /*
>> + * Realm and Non-secure share the same page-local offset layout; Secure uses
>> + * the same layout but is mapped starting at 0x8000(SMMU_SECURE_REG_START)
>> + */
>> + if (offset >= SMMU_SECURE_REG_START) {
>> + reg_sec_sid = SMMU_SEC_SID_S;
>> + }
>> +
>> switch (size) {
>> case 8:
>> - r = smmu_writell(s, offset, data, attrs);
>> + r = smmu_writell(s, offset, data, attrs, reg_sec_sid);
>> break;
>> case 4:
>> - r = smmu_writel(s, offset, data, attrs);
>> + r = smmu_writel(s, offset, data, attrs, reg_sec_sid);
>> break;
>> default:
>> r = MEMTX_ERROR;
>> @@ -2115,12 +2126,13 @@ static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t data,
>> }
>>
>> static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
>> - uint64_t *data, MemTxAttrs attrs)
>> + uint64_t *data, MemTxAttrs attrs,
>> + SMMUSecSID reg_sec_sid)
>> {
>> - SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
>> SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
>> + uint32_t reg_offset = offset & 0xfff;
>>
>> - switch (offset) {
>> + switch (reg_offset) {
>> case A_GERROR_IRQ_CFG0:
>> /* SMMU_(*_)GERROR_IRQ_CFG0 BOTH check SMMU_IDR0.MSI */
>> if (!smmu_msi_supported(s)) {
>> @@ -2149,17 +2161,22 @@ static MemTxResult smmu_readll(SMMUv3State *s, hwaddr offset,
>> }
>>
>> static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
>> - uint64_t *data, MemTxAttrs attrs)
>> + uint64_t *data, MemTxAttrs attrs,
>> + SMMUSecSID reg_sec_sid)
>> {
>> - SMMUSecSID reg_sec_sid = SMMU_SEC_SID_NS;
>> SMMUv3RegBank *bank = smmuv3_bank(s, reg_sec_sid);
>> + uint32_t reg_offset = offset & 0xfff;
>>
>> - switch (offset) {
>> + switch (reg_offset) {
>> case A_IDREGS ... A_IDREGS + 0x2f:
>> - *data = smmuv3_idreg(offset - A_IDREGS);
>> + *data = smmuv3_idreg(reg_offset - A_IDREGS);
>> return MEMTX_OK;
>> case A_IDR0 ... A_IDR5:
>> - *data = bank->idr[(offset - A_IDR0) / 4];
>> + if (reg_sec_sid == SMMU_SEC_SID_S) {
>> + g_assert((reg_offset - A_IDR0) / 4 < 5);
> Asserting here is too much as this can be easily triggered by guests,
> we should follow the convention of other unimplemented registers.
I'll fix it in V5.
>
> Thanks,
> Mostafa
Thanks for your time!
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 25/31] hw/arm/smmuv3: Implement SMMU_S_INIT register
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (23 preceding siblings ...)
2026-02-21 10:18 ` [RFC v4 24/31] hw/arm/smmuv3: Determine register bank from MMIO offset Tao Tang
@ 2026-02-21 10:18 ` Tao Tang
2026-02-25 22:01 ` Pierrick Bouvier
2026-02-21 10:18 ` [RFC v4 26/31] hw/arm/smmuv3: Harden security checks in MMIO handlers Tao Tang
` (5 subsequent siblings)
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:18 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Implement read/write handlers for the SMMU_S_INIT secure-only register.
Writing INV_ALL provides a mechanism for software to perform a global
invalidation of ALL caches within the SMMU, including IOTLBs and
configuration caches across all security states.
The MMIO dispatcher decodes the target register bank from the high bits
of the offset and then switches on the 4KB page-local offset
(offset & 0xfff), since registers that share the same function across
banks use the same relative layout. S_INIT is a secure-only register and
its A_S_INIT constant is currently defined as an absolute secure-window
offset (0x803c), so it has no NS twin to reuse as a shared low-12-bit
macro. As a one-off special case, the handler matches it via
(A_S_INIT & 0xfff) to fit the relative-offset decode.
This feature is critical for secure hypervisors like Hafnium, which use
it as a final step in their SMMU initialization sequence to ensure a
clean cache state before enabling translations.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 37 +++++++++++++++++++++++++++++++++++++
hw/arm/trace-events | 1 +
2 files changed, 38 insertions(+)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index d81485a6a46..6fd664a000f 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -373,6 +373,21 @@ static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
}
+static void smmuv3_invalidate_all_caches(SMMUv3State *s)
+{
+ SMMUState *bs = &s->smmu_state;
+ trace_smmuv3_invalidate_all_caches();
+
+ /* Clear all cached configs including STE and CD */
+ if (bs->configs) {
+ g_hash_table_remove_all(bs->configs);
+ }
+
+ /* Invalidate all SMMU IOTLB entries */
+ smmu_inv_notifiers_all(&s->smmu_state);
+ smmu_iotlb_inv_all(bs, SMMU_SEC_SID_NUM);
+}
+
static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
SMMUTransCfg *cfg,
SMMUEventInfo *event,
@@ -2077,6 +2092,25 @@ static MemTxResult smmu_writel(SMMUv3State *s, hwaddr offset,
bank->eventq_irq_cfg2 = data;
break;
+ /* S_INIT is Secure-only. So match it as a one-off via & 0xfff. */
+ case (A_S_INIT & 0xfff):
+ if (data & R_S_INIT_INV_ALL_MASK) {
+ /*
+ * If SMMU_ROOT_CR0.GPCEN == 0, a write of 1 to INV_ALL when any
+ * SMMU_(*_)CR0.SMMUEN == 1, .... , is CONSTRAINED UNPREDICTABLE
+ * according to (IHI 0070G.b) 6.3.62 SMMU_S_INIT, Page 465.
+ */
+ if (!smmuv3_smmu_disabled_stable(s, SMMU_SEC_SID_NS) ||
+ !smmuv3_smmu_disabled_stable(s, SMMU_SEC_SID_S)) {
+ /* CONSTRAINED UNPREDICTABLE behavior: Ignore this write */
+ qemu_log_mask(LOG_GUEST_ERROR, "S_INIT write ignored: "
+ "(S_)CR0.SMMUEN or (S_)CR0ACK.SMMUEN is set\n");
+ return MEMTX_OK;
+ }
+ smmuv3_invalidate_all_caches(s);
+ }
+ /* Synchronous emulation: invalidation completed instantly. */
+ break;
default:
qemu_log_mask(LOG_UNIMP,
"%s Unexpected 32-bit access to 0x%"PRIx64" (WI)\n",
@@ -2277,6 +2311,9 @@ static MemTxResult smmu_readl(SMMUv3State *s, hwaddr offset,
case A_EVENTQ_CONS:
*data = bank->eventq.cons;
return MEMTX_OK;
+ case (A_S_INIT & 0xfff):
+ *data = 0;
+ return MEMTX_OK;
default:
*data = 0;
qemu_log_mask(LOG_UNIMP,
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index 64f308a8d35..26f19f18cb7 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -64,6 +64,7 @@ smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
smmuv3_notify_flag_add(const char *iommu) "ADD SMMUNotifier node for iommu mr=%s"
smmuv3_notify_flag_del(const char *iommu) "DEL SMMUNotifier node for iommu mr=%s"
smmuv3_inv_notifiers_iova(const char *name, int asid, int vmid, uint64_t iova, uint8_t tg, uint64_t num_pages, int stage) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" stage=%d"
+smmuv3_invalidate_all_caches(void) "Invalidate all SMMU caches and TLBs"
smmu_reset_exit(void) ""
#smmuv3-accel.c
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 25/31] hw/arm/smmuv3: Implement SMMU_S_INIT register
2026-02-21 10:18 ` [RFC v4 25/31] hw/arm/smmuv3: Implement SMMU_S_INIT register Tao Tang
@ 2026-02-25 22:01 ` Pierrick Bouvier
0 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 22:01 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:18 AM, Tao Tang wrote:
> Implement read/write handlers for the SMMU_S_INIT secure-only register.
>
> Writing INV_ALL provides a mechanism for software to perform a global
> invalidation of ALL caches within the SMMU, including IOTLBs and
> configuration caches across all security states.
>
> The MMIO dispatcher decodes the target register bank from the high bits
> of the offset and then switches on the 4KB page-local offset
> (offset & 0xfff), since registers that share the same function across
> banks use the same relative layout. S_INIT is a secure-only register and
> its A_S_INIT constant is currently defined as an absolute secure-window
> offset (0x803c), so it has no NS twin to reuse as a shared low-12-bit
> macro. As a one-off special case, the handler matches it via
> (A_S_INIT & 0xfff) to fit the relative-offset decode.
>
> This feature is critical for secure hypervisors like Hafnium, which use
> it as a final step in their SMMU initialization sequence to ensure a
> clean cache state before enabling translations.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 37 +++++++++++++++++++++++++++++++++++++
> hw/arm/trace-events | 1 +
> 2 files changed, 38 insertions(+)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 26/31] hw/arm/smmuv3: Harden security checks in MMIO handlers
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (24 preceding siblings ...)
2026-02-21 10:18 ` [RFC v4 25/31] hw/arm/smmuv3: Implement SMMU_S_INIT register Tao Tang
@ 2026-02-21 10:18 ` Tao Tang
2026-02-25 22:03 ` Pierrick Bouvier
2026-02-21 10:18 ` [RFC v4 27/31] hw/pci: Add sec-sid property to PCIDevice Tao Tang
` (4 subsequent siblings)
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:18 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
This patch hardens the security validation within the main MMIO
dispatcher functions (smmu_read_mmio and smmu_write_mmio).
First, accesses to the secure register space are now correctly gated by
whether the SECURE_IMPL feature is enabled in the model. This prevents
guest software from accessing the secure programming interface when it is
disabled, though some registers are exempt from this check as per the
architecture.
Second, the check for the input stream's security is made more robust.
It now validates not only the legacy MemTxAttrs.secure bit, but also
the .space field. This improves compatibility with Arm security space
handling.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 80 insertions(+)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 6fd664a000f..0b8ea922851 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1503,6 +1503,12 @@ static bool smmu_eventq_irq_cfg_writable(SMMUv3State *s, SMMUSecSID sec_sid)
return (FIELD_EX32(s->bank[sec_sid].irq_ctrl, IRQ_CTRL, EVENTQ_IRQEN) == 0);
}
+/* Check if the SMMU hardware itself implements secure state features */
+static inline bool smmu_hw_secure_implemented(SMMUv3State *s)
+{
+ return FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1, SECURE_IMPL);
+}
+
static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
{
SMMUState *bs = ARM_SMMU(s);
@@ -1795,6 +1801,63 @@ static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
return 0;
}
+/*
+ * Check if a register is exempt from the secure implementation check.
+ *
+ * The SMMU architecture specifies that certain secure registers, such as
+ * the secure Event Queue IRQ configuration registers, must be accessible
+ * even if the full secure hardware is not implemented. This function
+ * identifies those registers.
+ *
+ * Returns true if the register is exempt, false otherwise.
+ */
+static bool is_secure_impl_exempt_reg(hwaddr offset)
+{
+ switch (offset) {
+ case A_S_EVENTQ_IRQ_CFG0:
+ case A_S_EVENTQ_IRQ_CFG1:
+ case A_S_EVENTQ_IRQ_CFG2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/*
+ * Helper function for Secure register access validation.
+ *
+ * Follow S_IDR1.SECURE_IMPL accessibility rules for SMMU_S_*:
+ * - SECURE_IMPL == 0: Secure state is not implemented; SMMU_S_* are RAZ/WI to
+ * all accesses.
+ * - SECURE_IMPL == 1: Non-secure accesses to SMMU_S_* are RAZ/WI.
+ */
+static bool smmu_check_secure_access(SMMUv3State *s, MemTxAttrs attrs,
+ hwaddr offset, bool is_read)
+{
+ /* Check if the access is secure */
+ if (!(attrs.space == ARMSS_Secure ||
+ attrs.secure == 1)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Non-secure %s attempt at offset 0x%" PRIx64 " (%s)\n",
+ __func__, is_read ? "read" : "write", offset,
+ is_read ? "RAZ" : "WI");
+ return false;
+ }
+
+ /*
+ * Check if the secure state is implemented. Some registers are exempted
+ * from this check.
+ */
+ if (!is_secure_impl_exempt_reg(offset) && !smmu_hw_secure_implemented(s)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: Secure %s attempt at offset 0x%" PRIx64 ". But Secure state "
+ "is not implemented (RES0)\n",
+ __func__, is_read ? "read" : "write", offset);
+ return false;
+ }
+ return true;
+}
+
static MemTxResult smmu_writell(SMMUv3State *s, hwaddr offset,
uint64_t data, MemTxAttrs attrs,
SMMUSecSID reg_sec_sid)
@@ -2140,6 +2203,18 @@ static MemTxResult smmu_write_mmio(void *opaque, hwaddr offset, uint64_t data,
* the same layout but is mapped starting at 0x8000(SMMU_SECURE_REG_START)
*/
if (offset >= SMMU_SECURE_REG_START) {
+ if (!smmu_check_secure_access(s, attrs, offset, false)) {
+ trace_smmuv3_write_mmio(offset, data, size, MEMTX_OK);
+ /*
+ * RAZ/WI/RES0 are deterministic register-level behaviors and do not
+ * imply a bus protocol error or abort. Therefore we acknowledge the
+ * MMIO transaction with MEMTX_OK and implement
+ * "Read-As-Zero / Write-Ignored" in the register model, instead of
+ * returning MEMTX_*_ERROR which is reserved for real decode/access
+ * failures.
+ */
+ return MEMTX_OK;
+ }
reg_sec_sid = SMMU_SEC_SID_S;
}
@@ -2334,6 +2409,11 @@ static MemTxResult smmu_read_mmio(void *opaque, hwaddr offset, uint64_t *data,
/* CONSTRAINED UNPREDICTABLE choice to have page0/1 be exact aliases */
offset &= ~0x10000;
if (offset >= SMMU_SECURE_REG_START) {
+ if (!smmu_check_secure_access(s, attrs, offset, true)) {
+ *data = 0;
+ trace_smmuv3_read_mmio(offset, *data, size, MEMTX_OK);
+ return MEMTX_OK;
+ }
reg_sec_sid = SMMU_SEC_SID_S;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 26/31] hw/arm/smmuv3: Harden security checks in MMIO handlers
2026-02-21 10:18 ` [RFC v4 26/31] hw/arm/smmuv3: Harden security checks in MMIO handlers Tao Tang
@ 2026-02-25 22:03 ` Pierrick Bouvier
0 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 22:03 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:18 AM, Tao Tang wrote:
> This patch hardens the security validation within the main MMIO
> dispatcher functions (smmu_read_mmio and smmu_write_mmio).
>
> First, accesses to the secure register space are now correctly gated by
> whether the SECURE_IMPL feature is enabled in the model. This prevents
> guest software from accessing the secure programming interface when it is
> disabled, though some registers are exempt from this check as per the
> architecture.
>
> Second, the check for the input stream's security is made more robust.
> It now validates not only the legacy MemTxAttrs.secure bit, but also
> the .space field. This improves compatibility with Arm security space
> handling.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 80 insertions(+)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 27/31] hw/pci: Add sec-sid property to PCIDevice
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (25 preceding siblings ...)
2026-02-21 10:18 ` [RFC v4 26/31] hw/arm/smmuv3: Harden security checks in MMIO handlers Tao Tang
@ 2026-02-21 10:18 ` Tao Tang
2026-02-25 22:05 ` Pierrick Bouvier
2026-02-21 10:19 ` [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL Tao Tang
` (3 subsequent siblings)
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:18 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Arm SMMUv3 uses a SEC_SID (StreamID Security state) to determine the
security state of the programming interface that controls a transaction.
The architecture explicitly states that the association between a device
and its SEC_SID is a system-defined property, not something derived from
the physical address space.
We need a way to represent this system-defined SEC_SID for PCI devices
if we want to implement SMMU's Secure state. So that SMMUv3 can select
the correct register bank and configuration when handling their streams.
This patch adds a new char *sec_sid field to PCIDevice, together with
a "sec-sid" QOM property. The property is intended to carry the
platform-defined SEC_SID for the device; for now only Non-secure and
Secure security states are supported.
Future RME-DA/TDISP work will use the PCIe TDISP/DTI protocol to model
Realm and Non-secure streams, instead of extending this static field.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/pci/pci.c | 7 +++++++
include/hw/pci/pci_device.h | 3 +++
2 files changed, 10 insertions(+)
diff --git a/hw/pci/pci.c b/hw/pci/pci.c
index 90d6d71efdc..aca0509f705 100644
--- a/hw/pci/pci.c
+++ b/hw/pci/pci.c
@@ -98,6 +98,13 @@ static const Property pci_props[] = {
DEFINE_PROP_STRING("sriov-pf", PCIDevice, sriov_pf),
DEFINE_PROP_BIT("x-pcie-ext-tag", PCIDevice, cap_present,
QEMU_PCIE_EXT_TAG_BITNR, true),
+
+ /*
+ * System-defined, statically configured SEC_SID for this PCI device, used
+ * by Arm SMMU. Only support "non-secure" and "secure" security states.
+ */
+ DEFINE_PROP_STRING("sec-sid", PCIDevice, sec_sid),
+
{ .name = "busnr", .info = &prop_pci_busnr },
};
diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h
index 88ccea50113..47ed4a13e40 100644
--- a/include/hw/pci/pci_device.h
+++ b/include/hw/pci/pci_device.h
@@ -184,6 +184,9 @@ struct PCIDevice {
uint32_t max_bounce_buffer_size;
char *sriov_pf;
+
+ /* Arm SMMU SEC_SID */
+ char *sec_sid;
};
static inline int pci_intx(PCIDevice *pci_dev)
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 27/31] hw/pci: Add sec-sid property to PCIDevice
2026-02-21 10:18 ` [RFC v4 27/31] hw/pci: Add sec-sid property to PCIDevice Tao Tang
@ 2026-02-25 22:05 ` Pierrick Bouvier
0 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 22:05 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:18 AM, Tao Tang wrote:
> Arm SMMUv3 uses a SEC_SID (StreamID Security state) to determine the
> security state of the programming interface that controls a transaction.
> The architecture explicitly states that the association between a device
> and its SEC_SID is a system-defined property, not something derived from
> the physical address space.
>
> We need a way to represent this system-defined SEC_SID for PCI devices
> if we want to implement SMMU's Secure state. So that SMMUv3 can select
> the correct register bank and configuration when handling their streams.
>
> This patch adds a new char *sec_sid field to PCIDevice, together with
> a "sec-sid" QOM property. The property is intended to carry the
> platform-defined SEC_SID for the device; for now only Non-secure and
> Secure security states are supported.
>
> Future RME-DA/TDISP work will use the PCIe TDISP/DTI protocol to model
> Realm and Non-secure streams, instead of extending this static field.
>
In practice, it's not yet clear how will get this TDISP T-bit, since
it's part of encrypted payload. So far, we are detecting config fetch
and dynamically switching a given device to a new sec_sid accordingly.
Thus, we *might* end up reusing this field eventually.
All that said, for now, and in the context of this series, it's
definitely a static property.
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/pci/pci.c | 7 +++++++
> include/hw/pci/pci_device.h | 3 +++
> 2 files changed, 10 insertions(+)
>
> diff --git a/hw/pci/pci.c b/hw/pci/pci.c
> index 90d6d71efdc..aca0509f705 100644
> --- a/hw/pci/pci.c
> +++ b/hw/pci/pci.c
> @@ -98,6 +98,13 @@ static const Property pci_props[] = {
> DEFINE_PROP_STRING("sriov-pf", PCIDevice, sriov_pf),
> DEFINE_PROP_BIT("x-pcie-ext-tag", PCIDevice, cap_present,
> QEMU_PCIE_EXT_TAG_BITNR, true),
> +
> + /*
> + * System-defined, statically configured SEC_SID for this PCI device, used
> + * by Arm SMMU. Only support "non-secure" and "secure" security states.
> + */
> + DEFINE_PROP_STRING("sec-sid", PCIDevice, sec_sid),
> +
> { .name = "busnr", .info = &prop_pci_busnr },
> };
>
> diff --git a/include/hw/pci/pci_device.h b/include/hw/pci/pci_device.h
> index 88ccea50113..47ed4a13e40 100644
> --- a/include/hw/pci/pci_device.h
> +++ b/include/hw/pci/pci_device.h
> @@ -184,6 +184,9 @@ struct PCIDevice {
> uint32_t max_bounce_buffer_size;
>
> char *sriov_pf;
> +
> + /* Arm SMMU SEC_SID */
> + char *sec_sid;
> };
>
> static inline int pci_intx(PCIDevice *pci_dev)
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (26 preceding siblings ...)
2026-02-21 10:18 ` [RFC v4 27/31] hw/pci: Add sec-sid property to PCIDevice Tao Tang
@ 2026-02-21 10:19 ` Tao Tang
2026-02-25 22:10 ` Pierrick Bouvier
` (3 more replies)
2026-02-21 10:19 ` [RFC v4 29/31] hw/arm/smmuv3: Initialize the secure register bank Tao Tang
` (2 subsequent siblings)
30 siblings, 4 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:19 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Parse each PCI device's sec-sid property during SMMU device initialization
and cache it in SMMUDevice::sec_sid. Support "non-secure" and "secure",
default to non-secure when unspecified, and reject invalid values with an
explicit error. Use sdev->sec_sid in smmuv3_translate() to select the
register bank instead of hardcoding the non-secure context.
Keep sec-sid parsing in smmu-common, and add a SMMUv3-specific validation
hook to enforce architectural constraints: fail fast when sec-sid=secure
while SMMU_S_IDR1.SECURE_IMPL is 0 or secure AS is not available.
Typically, SEC_SID is a system-defined attribute (e.g. sideband or tied-off)
rather than something a PCIe endpoint can freely toggle in pre-RME scenario.
So this PCI sec-sid property is used as a static platform/testing knob to
drive the SMMU bank selection.
For future RME-DA + TDISP, this will need to become dynamic: the effective
state for PCIe requests is derived from PCIe IDE/TDISP T/XT
(e.g. SEC_SID = (XT || T) ? Realm : Non-secure), so we'll switch from a
static property to a runtime per-device state update when that plumbing
is added.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmu-common.c | 37 ++++++++++++++++++++++++++++++++++++
hw/arm/smmuv3.c | 34 ++++++++++++++++++++++++++++++++-
include/hw/arm/smmu-common.h | 2 ++
3 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 5dece2024a4..b0a238abe93 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -21,6 +21,7 @@
#include "exec/target_page.h"
#include "hw/core/cpu.h"
#include "hw/pci/pci_bridge.h"
+#include "hw/pci/pci_device.h"
#include "hw/core/qdev-properties.h"
#include "qapi/error.h"
#include "qemu/jhash.h"
@@ -1071,14 +1072,50 @@ SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num)
return NULL;
}
+static SMMUSecSID smmu_parse_pci_sec_sid(PCIDevice *pdev, int bus_num,
+ int devfn)
+{
+ const char *sec_sid;
+
+ if (!pdev || !pdev->sec_sid) {
+ return SMMU_SEC_SID_NS;
+ }
+
+ sec_sid = pdev->sec_sid;
+ if (!strcmp(sec_sid, "non-secure")) {
+ return SMMU_SEC_SID_NS;
+ }
+ if (!strcmp(sec_sid, "secure")) {
+ return SMMU_SEC_SID_S;
+ }
+
+ error_report("Invalid sec-sid value '%s' for PCI device %02x:%02x.%x; "
+ "allowed values: non-secure or secure (case-sensitive)",
+ sec_sid, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn));
+ exit(EXIT_FAILURE);
+}
+
void smmu_init_sdev(SMMUState *s, SMMUDevice *sdev, PCIBus *bus, int devfn)
{
static unsigned int index;
g_autofree char *name = g_strdup_printf("%s-%d-%d", s->mrtypename, devfn,
index++);
+ SMMUBaseClass *sbc = ARM_SMMU_GET_CLASS(s);
+ PCIDevice *pdev;
+ int bus_num;
+
sdev->smmu = s;
sdev->bus = bus;
sdev->devfn = devfn;
+ sdev->sec_sid = SMMU_SEC_SID_NS;
+
+ bus_num = pci_bus_num(bus);
+ pdev = pci_find_device(bus, bus_num, devfn);
+ sdev->sec_sid = smmu_parse_pci_sec_sid(pdev, bus_num, devfn);
+ if (sbc->validate_sec_sid &&
+ !sbc->validate_sec_sid(s, sdev, bus_num)) {
+ exit(EXIT_FAILURE);
+ }
memory_region_init_iommu(&sdev->iommu, sizeof(sdev->iommu),
s->mrtypename, OBJECT(s), name, UINT64_MAX);
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 0b8ea922851..57a063b5e5d 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1116,7 +1116,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
SMMUv3State *s = sdev->smmu;
uint32_t sid = smmu_get_sid(sdev);
- SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
+ SMMUSecSID sec_sid = sdev->sec_sid;
SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
SMMUEventInfo event = {.type = SMMU_EVT_NONE,
.sid = sid,
@@ -1509,6 +1509,36 @@ static inline bool smmu_hw_secure_implemented(SMMUv3State *s)
return FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1, SECURE_IMPL);
}
+static bool smmuv3_validate_sec_sid(SMMUState *bs, SMMUDevice *sdev,
+ int bus_num)
+{
+ SMMUv3State *s = ARM_SMMUV3(bs);
+ bool secure_as_available = bs->secure_memory &&
+ bs->secure_memory_as.root != NULL;
+
+ if (sdev->sec_sid != SMMU_SEC_SID_S) {
+ return true;
+ }
+
+ if (!smmu_hw_secure_implemented(s)) {
+ error_report("Invalid sec-sid value 'secure' for PCI device "
+ "%02x:%02x.%x: S_IDR1.SECURE_IMPL is 0, so only "
+ "non-secure is allowed",
+ bus_num, PCI_SLOT(sdev->devfn), PCI_FUNC(sdev->devfn));
+ return false;
+ }
+
+ if (!secure_as_available) {
+ error_report("Invalid sec-sid value 'secure' for PCI device "
+ "%02x:%02x.%x: secure-memory address space is not "
+ "configured",
+ bus_num, PCI_SLOT(sdev->devfn), PCI_FUNC(sdev->devfn));
+ return false;
+ }
+
+ return true;
+}
+
static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
{
SMMUState *bs = ARM_SMMU(s);
@@ -2664,6 +2694,7 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
DeviceClass *dc = DEVICE_CLASS(klass);
ResettableClass *rc = RESETTABLE_CLASS(klass);
SMMUv3Class *c = ARM_SMMUV3_CLASS(klass);
+ SMMUBaseClass *sbc = ARM_SMMU_CLASS(klass);
dc->vmsd = &vmstate_smmuv3;
resettable_class_set_parent_phases(rc, NULL, NULL, smmu_reset_exit,
@@ -2673,6 +2704,7 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
device_class_set_props(dc, smmuv3_properties);
dc->hotpluggable = false;
dc->user_creatable = true;
+ sbc->validate_sec_sid = smmuv3_validate_sec_sid;
object_class_property_set_description(klass, "accel",
"Enable SMMUv3 accelerator support. Allows host SMMUv3 to be "
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index d05cf6ae53b..c74f66a1bb9 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -144,6 +144,7 @@ typedef struct SMMUDevice {
void *smmu;
PCIBus *bus;
int devfn;
+ SMMUSecSID sec_sid;
IOMMUMemoryRegion iommu;
AddressSpace as;
uint32_t cfg_cache_hits;
@@ -204,6 +205,7 @@ struct SMMUBaseClass {
/*< public >*/
DeviceRealize parent_realize;
+ bool (*validate_sec_sid)(struct SMMUState *s, SMMUDevice *sdev, int bus_num);
};
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL
2026-02-21 10:19 ` [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL Tao Tang
@ 2026-02-25 22:10 ` Pierrick Bouvier
2026-02-25 22:12 ` Pierrick Bouvier
` (2 subsequent siblings)
3 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 22:10 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:19 AM, Tao Tang wrote:
> Parse each PCI device's sec-sid property during SMMU device initialization
> and cache it in SMMUDevice::sec_sid. Support "non-secure" and "secure",
> default to non-secure when unspecified, and reject invalid values with an
> explicit error. Use sdev->sec_sid in smmuv3_translate() to select the
> register bank instead of hardcoding the non-secure context.
>
> Keep sec-sid parsing in smmu-common, and add a SMMUv3-specific validation
> hook to enforce architectural constraints: fail fast when sec-sid=secure
> while SMMU_S_IDR1.SECURE_IMPL is 0 or secure AS is not available.
>
> Typically, SEC_SID is a system-defined attribute (e.g. sideband or tied-off)
> rather than something a PCIe endpoint can freely toggle in pre-RME scenario.
> So this PCI sec-sid property is used as a static platform/testing knob to
> drive the SMMU bank selection.
>
> For future RME-DA + TDISP, this will need to become dynamic: the effective
> state for PCIe requests is derived from PCIe IDE/TDISP T/XT
> (e.g. SEC_SID = (XT || T) ? Realm : Non-secure), so we'll switch from a
> static property to a runtime per-device state update when that plumbing
> is added.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 37 ++++++++++++++++++++++++++++++++++++
> hw/arm/smmuv3.c | 34 ++++++++++++++++++++++++++++++++-
> include/hw/arm/smmu-common.h | 2 ++
> 3 files changed, 72 insertions(+), 1 deletion(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL
2026-02-21 10:19 ` [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL Tao Tang
2026-02-25 22:10 ` Pierrick Bouvier
@ 2026-02-25 22:12 ` Pierrick Bouvier
2026-03-03 10:47 ` Eric Auger
2026-03-03 10:48 ` Eric Auger
3 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 22:12 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:19 AM, Tao Tang wrote:
> Parse each PCI device's sec-sid property during SMMU device initialization
> and cache it in SMMUDevice::sec_sid. Support "non-secure" and "secure",
> default to non-secure when unspecified, and reject invalid values with an
> explicit error. Use sdev->sec_sid in smmuv3_translate() to select the
> register bank instead of hardcoding the non-secure context.
>
> Keep sec-sid parsing in smmu-common, and add a SMMUv3-specific validation
> hook to enforce architectural constraints: fail fast when sec-sid=secure
> while SMMU_S_IDR1.SECURE_IMPL is 0 or secure AS is not available.
>
> Typically, SEC_SID is a system-defined attribute (e.g. sideband or tied-off)
> rather than something a PCIe endpoint can freely toggle in pre-RME scenario.
> So this PCI sec-sid property is used as a static platform/testing knob to
> drive the SMMU bank selection.
>
> For future RME-DA + TDISP, this will need to become dynamic: the effective
> state for PCIe requests is derived from PCIe IDE/TDISP T/XT
> (e.g. SEC_SID = (XT || T) ? Realm : Non-secure), so we'll switch from a
> static property to a runtime per-device state update when that plumbing
> is added.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 37 ++++++++++++++++++++++++++++++++++++
> hw/arm/smmuv3.c | 34 ++++++++++++++++++++++++++++++++-
> include/hw/arm/smmu-common.h | 2 ++
> 3 files changed, 72 insertions(+), 1 deletion(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL
2026-02-21 10:19 ` [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL Tao Tang
2026-02-25 22:10 ` Pierrick Bouvier
2026-02-25 22:12 ` Pierrick Bouvier
@ 2026-03-03 10:47 ` Eric Auger
2026-03-06 13:30 ` Tao Tang
2026-03-03 10:48 ` Eric Auger
3 siblings, 1 reply; 136+ messages in thread
From: Eric Auger @ 2026-03-03 10:47 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 2/21/26 11:19 AM, Tao Tang wrote:
> Parse each PCI device's sec-sid property during SMMU device initialization
> and cache it in SMMUDevice::sec_sid. Support "non-secure" and "secure",
> default to non-secure when unspecified, and reject invalid values with an
> explicit error. Use sdev->sec_sid in smmuv3_translate() to select the
> register bank instead of hardcoding the non-secure context.
>
> Keep sec-sid parsing in smmu-common, and add a SMMUv3-specific validation
> hook to enforce architectural constraints: fail fast when sec-sid=secure
> while SMMU_S_IDR1.SECURE_IMPL is 0 or secure AS is not available.
>
> Typically, SEC_SID is a system-defined attribute (e.g. sideband or tied-off)
> rather than something a PCIe endpoint can freely toggle in pre-RME scenario.
> So this PCI sec-sid property is used as a static platform/testing knob to
> drive the SMMU bank selection.
>
> For future RME-DA + TDISP, this will need to become dynamic: the effective
> state for PCIe requests is derived from PCIe IDE/TDISP T/XT
> (e.g. SEC_SID = (XT || T) ? Realm : Non-secure), so we'll switch from a
> static property to a runtime per-device state update when that plumbing
> is added.
When a translation is triggered, address_space_translate_iommu passes attrs.
MemTxAttrs.secure bit should tell you whether the translation is
requested in secure mode.
Shouldn't we pass that information the smmuv3 translate function()?
In address_space_translate_iommu I see:
if (imrc->attrs_to_index) {
iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
}
iotlb = imrc->translate(iommu_mr, addr, is_write ?
IOMMU_WO : IOMMU_RO, iommu_idx);
Thanks
Eric
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 37 ++++++++++++++++++++++++++++++++++++
> hw/arm/smmuv3.c | 34 ++++++++++++++++++++++++++++++++-
> include/hw/arm/smmu-common.h | 2 ++
> 3 files changed, 72 insertions(+), 1 deletion(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index 5dece2024a4..b0a238abe93 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -21,6 +21,7 @@
> #include "exec/target_page.h"
> #include "hw/core/cpu.h"
> #include "hw/pci/pci_bridge.h"
> +#include "hw/pci/pci_device.h"
> #include "hw/core/qdev-properties.h"
> #include "qapi/error.h"
> #include "qemu/jhash.h"
> @@ -1071,14 +1072,50 @@ SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num)
> return NULL;
> }
>
> +static SMMUSecSID smmu_parse_pci_sec_sid(PCIDevice *pdev, int bus_num,
> + int devfn)
> +{
> + const char *sec_sid;
> +
> + if (!pdev || !pdev->sec_sid) {
> + return SMMU_SEC_SID_NS;
> + }
> +
> + sec_sid = pdev->sec_sid;
> + if (!strcmp(sec_sid, "non-secure")) {
> + return SMMU_SEC_SID_NS;
> + }
> + if (!strcmp(sec_sid, "secure")) {
> + return SMMU_SEC_SID_S;
> + }
> +
> + error_report("Invalid sec-sid value '%s' for PCI device %02x:%02x.%x; "
> + "allowed values: non-secure or secure (case-sensitive)",
> + sec_sid, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn));
> + exit(EXIT_FAILURE);
> +}
> +
> void smmu_init_sdev(SMMUState *s, SMMUDevice *sdev, PCIBus *bus, int devfn)
> {
> static unsigned int index;
> g_autofree char *name = g_strdup_printf("%s-%d-%d", s->mrtypename, devfn,
> index++);
> + SMMUBaseClass *sbc = ARM_SMMU_GET_CLASS(s);
> + PCIDevice *pdev;
> + int bus_num;
> +
> sdev->smmu = s;
> sdev->bus = bus;
> sdev->devfn = devfn;
> + sdev->sec_sid = SMMU_SEC_SID_NS;
> +
> + bus_num = pci_bus_num(bus);
> + pdev = pci_find_device(bus, bus_num, devfn);
> + sdev->sec_sid = smmu_parse_pci_sec_sid(pdev, bus_num, devfn);
> + if (sbc->validate_sec_sid &&
> + !sbc->validate_sec_sid(s, sdev, bus_num)) {
> + exit(EXIT_FAILURE);
> + }
>
> memory_region_init_iommu(&sdev->iommu, sizeof(sdev->iommu),
> s->mrtypename, OBJECT(s), name, UINT64_MAX);
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 0b8ea922851..57a063b5e5d 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1116,7 +1116,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
> SMMUv3State *s = sdev->smmu;
> uint32_t sid = smmu_get_sid(sdev);
> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUSecSID sec_sid = sdev->sec_sid;
> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> SMMUEventInfo event = {.type = SMMU_EVT_NONE,
> .sid = sid,
> @@ -1509,6 +1509,36 @@ static inline bool smmu_hw_secure_implemented(SMMUv3State *s)
> return FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1, SECURE_IMPL);
> }
>
> +static bool smmuv3_validate_sec_sid(SMMUState *bs, SMMUDevice *sdev,
> + int bus_num)
> +{
> + SMMUv3State *s = ARM_SMMUV3(bs);
> + bool secure_as_available = bs->secure_memory &&
> + bs->secure_memory_as.root != NULL;
> +
> + if (sdev->sec_sid != SMMU_SEC_SID_S) {
> + return true;
> + }
> +
> + if (!smmu_hw_secure_implemented(s)) {
> + error_report("Invalid sec-sid value 'secure' for PCI device "
> + "%02x:%02x.%x: S_IDR1.SECURE_IMPL is 0, so only "
> + "non-secure is allowed",
> + bus_num, PCI_SLOT(sdev->devfn), PCI_FUNC(sdev->devfn));
> + return false;
> + }
> +
> + if (!secure_as_available) {
> + error_report("Invalid sec-sid value 'secure' for PCI device "
> + "%02x:%02x.%x: secure-memory address space is not "
> + "configured",
> + bus_num, PCI_SLOT(sdev->devfn), PCI_FUNC(sdev->devfn));
> + return false;
> + }
> +
> + return true;
> +}
> +
> static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> {
> SMMUState *bs = ARM_SMMU(s);
> @@ -2664,6 +2694,7 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
> DeviceClass *dc = DEVICE_CLASS(klass);
> ResettableClass *rc = RESETTABLE_CLASS(klass);
> SMMUv3Class *c = ARM_SMMUV3_CLASS(klass);
> + SMMUBaseClass *sbc = ARM_SMMU_CLASS(klass);
>
> dc->vmsd = &vmstate_smmuv3;
> resettable_class_set_parent_phases(rc, NULL, NULL, smmu_reset_exit,
> @@ -2673,6 +2704,7 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
> device_class_set_props(dc, smmuv3_properties);
> dc->hotpluggable = false;
> dc->user_creatable = true;
> + sbc->validate_sec_sid = smmuv3_validate_sec_sid;
>
> object_class_property_set_description(klass, "accel",
> "Enable SMMUv3 accelerator support. Allows host SMMUv3 to be "
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index d05cf6ae53b..c74f66a1bb9 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -144,6 +144,7 @@ typedef struct SMMUDevice {
> void *smmu;
> PCIBus *bus;
> int devfn;
> + SMMUSecSID sec_sid;
> IOMMUMemoryRegion iommu;
> AddressSpace as;
> uint32_t cfg_cache_hits;
> @@ -204,6 +205,7 @@ struct SMMUBaseClass {
> /*< public >*/
>
> DeviceRealize parent_realize;
> + bool (*validate_sec_sid)(struct SMMUState *s, SMMUDevice *sdev, int bus_num);
>
> };
>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL
2026-03-03 10:47 ` Eric Auger
@ 2026-03-06 13:30 ` Tao Tang
2026-03-06 17:29 ` Pierrick Bouvier
0 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-03-06 13:30 UTC (permalink / raw)
To: eric.auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
Hi Eric,
On 2026/3/3 18:47, Eric Auger wrote:
> On 2/21/26 11:19 AM, Tao Tang wrote:
>> Parse each PCI device's sec-sid property during SMMU device initialization
>> and cache it in SMMUDevice::sec_sid. Support "non-secure" and "secure",
>> default to non-secure when unspecified, and reject invalid values with an
>> explicit error. Use sdev->sec_sid in smmuv3_translate() to select the
>> register bank instead of hardcoding the non-secure context.
>>
>> Keep sec-sid parsing in smmu-common, and add a SMMUv3-specific validation
>> hook to enforce architectural constraints: fail fast when sec-sid=secure
>> while SMMU_S_IDR1.SECURE_IMPL is 0 or secure AS is not available.
>>
>> Typically, SEC_SID is a system-defined attribute (e.g. sideband or tied-off)
>> rather than something a PCIe endpoint can freely toggle in pre-RME scenario.
>> So this PCI sec-sid property is used as a static platform/testing knob to
>> drive the SMMU bank selection.
>>
>> For future RME-DA + TDISP, this will need to become dynamic: the effective
>> state for PCIe requests is derived from PCIe IDE/TDISP T/XT
>> (e.g. SEC_SID = (XT || T) ? Realm : Non-secure), so we'll switch from a
>> static property to a runtime per-device state update when that plumbing
>> is added.
> When a translation is triggered, address_space_translate_iommu passes attrs.
> MemTxAttrs.secure bit should tell you whether the translation is
> requested in secure mode.
> Shouldn't we pass that information the smmuv3 translate function()?
>
> In address_space_translate_iommu I see:
> if (imrc->attrs_to_index) {
> iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
> }
>
> iotlb = imrc->translate(iommu_mr, addr, is_write ?
> IOMMU_WO : IOMMU_RO, iommu_idx);
Thanks for pointing this out.
I agree that per-transaction request intent should eventually come from
MemTxAttrs or attrs_to_index().
However, the current producer side is not yet in a state where
transaction attrs alone can replace stream-level security wiring: many
PCI DMA paths still use MEMTXATTRS_UNSPECIFIED, and space cannot be
consumed safely without an explicit validity signal. For example, an
incorrect zero-initialized or otherwise unspecified .space value cannot
be treated as authoritative by itself as Pierrick mentioned in this thread:
https://lore.kernel.org/qemu-devel/dbc4d33e-3477-4f39-a745-4fdc0866fc08@linaro.org/
In the current codebase, this can easily blur the distinction between
“explicitly Secure” and “not specified at all”, especially for legacy or
non-Arm-aware producers. So I think there are really two separate
concerns here:
1. the per-transaction intent (which should indeed come from MemTxAttrs
/ attrs_to_index()); and
2. the stream-level capability / wiring, i.e. whether this SID is
allowed to reach the Secure programming interface in the first place.
My concern with the current patch is not that attrs-based routing is the
wrong long-term direction, but that today transaction attrs are not yet
propagated consistently enough to replace a stream-level model entirely.
So for now, I think a static sec-sid property is still useful as a
platform knob, until producer-side propagation becomes reliable enough.
Once that is in place, I agree that the bank selection should ultimately
be driven through the standard per-transaction attrs path. How do you
think about it?
Best regards,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL
2026-03-06 13:30 ` Tao Tang
@ 2026-03-06 17:29 ` Pierrick Bouvier
0 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-03-06 17:29 UTC (permalink / raw)
To: Tao Tang, eric.auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 3/6/26 5:30 AM, Tao Tang wrote:
> Hi Eric,
>
> On 2026/3/3 18:47, Eric Auger wrote:
>> On 2/21/26 11:19 AM, Tao Tang wrote:
>>> Parse each PCI device's sec-sid property during SMMU device initialization
>>> and cache it in SMMUDevice::sec_sid. Support "non-secure" and "secure",
>>> default to non-secure when unspecified, and reject invalid values with an
>>> explicit error. Use sdev->sec_sid in smmuv3_translate() to select the
>>> register bank instead of hardcoding the non-secure context.
>>>
>>> Keep sec-sid parsing in smmu-common, and add a SMMUv3-specific validation
>>> hook to enforce architectural constraints: fail fast when sec-sid=secure
>>> while SMMU_S_IDR1.SECURE_IMPL is 0 or secure AS is not available.
>>>
>>> Typically, SEC_SID is a system-defined attribute (e.g. sideband or tied-off)
>>> rather than something a PCIe endpoint can freely toggle in pre-RME scenario.
>>> So this PCI sec-sid property is used as a static platform/testing knob to
>>> drive the SMMU bank selection.
>>>
>>> For future RME-DA + TDISP, this will need to become dynamic: the effective
>>> state for PCIe requests is derived from PCIe IDE/TDISP T/XT
>>> (e.g. SEC_SID = (XT || T) ? Realm : Non-secure), so we'll switch from a
>>> static property to a runtime per-device state update when that plumbing
>>> is added.
>> When a translation is triggered, address_space_translate_iommu passes attrs.
>> MemTxAttrs.secure bit should tell you whether the translation is
>> requested in secure mode.
>> Shouldn't we pass that information the smmuv3 translate function()?
>>
>> In address_space_translate_iommu I see:
>> if (imrc->attrs_to_index) {
>> iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
>> }
>>
>> iotlb = imrc->translate(iommu_mr, addr, is_write ?
>> IOMMU_WO : IOMMU_RO, iommu_idx);
>
>
> Thanks for pointing this out.
>
> I agree that per-transaction request intent should eventually come from
> MemTxAttrs or attrs_to_index().
>
> However, the current producer side is not yet in a state where
> transaction attrs alone can replace stream-level security wiring: many
> PCI DMA paths still use MEMTXATTRS_UNSPECIFIED, and space cannot be
> consumed safely without an explicit validity signal. For example, an
> incorrect zero-initialized or otherwise unspecified .space value cannot
> be treated as authoritative by itself as Pierrick mentioned in this thread:
>
> https://lore.kernel.org/qemu-devel/dbc4d33e-3477-4f39-a745-4fdc0866fc08@linaro.org/
>
> In the current codebase, this can easily blur the distinction between
> “explicitly Secure” and “not specified at all”, especially for legacy or
> non-Arm-aware producers. So I think there are really two separate
> concerns here:
>
> 1. the per-transaction intent (which should indeed come from MemTxAttrs
> / attrs_to_index()); and
> 2. the stream-level capability / wiring, i.e. whether this SID is
> allowed to reach the Secure programming interface in the first place.
>
> My concern with the current patch is not that attrs-based routing is the
> wrong long-term direction, but that today transaction attrs are not yet
> propagated consistently enough to replace a stream-level model entirely.
>
> So for now, I think a static sec-sid property is still useful as a
> platform knob, until producer-side propagation becomes reliable enough.
> Once that is in place, I agree that the bank selection should ultimately
> be driven through the standard per-transaction attrs path. How do you
> think about it?
>
As a complement of information, SMMU specification mentions:
```
3.10.1 StreamID Security state (SEC_SID)
Note: Whether a stream is under Secure control or not is a different
property to the target PA space of a transaction.
```
At the time, we checked with spec authors at Arm what was the exact
meaning, and they confirmed it was a builtin (static) property of the
system. A secure device will always be secure through execution.
Realms have a different approach, and PCI transport has the T bit for
that, to make it a dynamic property.
Of course, we can implement things differently than what spec says, but
I definitely see it as a design hint that it should be a property of the
device, and not of the transaction itself.
My 2 cents,
Pierrick
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL
2026-02-21 10:19 ` [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL Tao Tang
` (2 preceding siblings ...)
2026-03-03 10:47 ` Eric Auger
@ 2026-03-03 10:48 ` Eric Auger
3 siblings, 0 replies; 136+ messages in thread
From: Eric Auger @ 2026-03-03 10:48 UTC (permalink / raw)
To: Tao Tang, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu
On 2/21/26 11:19 AM, Tao Tang wrote:
> Parse each PCI device's sec-sid property during SMMU device initialization
> and cache it in SMMUDevice::sec_sid. Support "non-secure" and "secure",
> default to non-secure when unspecified, and reject invalid values with an
> explicit error. Use sdev->sec_sid in smmuv3_translate() to select the
> register bank instead of hardcoding the non-secure context.
>
> Keep sec-sid parsing in smmu-common, and add a SMMUv3-specific validation
> hook to enforce architectural constraints: fail fast when sec-sid=secure
> while SMMU_S_IDR1.SECURE_IMPL is 0 or secure AS is not available.
>
> Typically, SEC_SID is a system-defined attribute (e.g. sideband or tied-off)
> rather than something a PCIe endpoint can freely toggle in pre-RME scenario.
> So this PCI sec-sid property is used as a static platform/testing knob to
> drive the SMMU bank selection.
>
> For future RME-DA + TDISP, this will need to become dynamic: the effective
> state for PCIe requests is derived from PCIe IDE/TDISP T/XT
> (e.g. SEC_SID = (XT || T) ? Realm : Non-secure), so we'll switch from a
> static property to a runtime per-device state update when that plumbing
> is added.
When a translation is triggered, address_space_translate_iommu passes attrs.
MemTxAttrs.secure bit should tell you whether the translation is
requested in secure mode.
Shouldn't we pass that information the smmuv3 translate function()?
In address_space_translate_iommu I see:
if (imrc->attrs_to_index) {
iommu_idx = imrc->attrs_to_index(iommu_mr, attrs);
}
iotlb = imrc->translate(iommu_mr, addr, is_write ?
IOMMU_WO : IOMMU_RO, iommu_idx);
Thanks
Eric
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmu-common.c | 37 ++++++++++++++++++++++++++++++++++++
> hw/arm/smmuv3.c | 34 ++++++++++++++++++++++++++++++++-
> include/hw/arm/smmu-common.h | 2 ++
> 3 files changed, 72 insertions(+), 1 deletion(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index 5dece2024a4..b0a238abe93 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -21,6 +21,7 @@
> #include "exec/target_page.h"
> #include "hw/core/cpu.h"
> #include "hw/pci/pci_bridge.h"
> +#include "hw/pci/pci_device.h"
> #include "hw/core/qdev-properties.h"
> #include "qapi/error.h"
> #include "qemu/jhash.h"
> @@ -1071,14 +1072,50 @@ SMMUPciBus *smmu_find_smmu_pcibus(SMMUState *s, uint8_t bus_num)
> return NULL;
> }
>
> +static SMMUSecSID smmu_parse_pci_sec_sid(PCIDevice *pdev, int bus_num,
> + int devfn)
> +{
> + const char *sec_sid;
> +
> + if (!pdev || !pdev->sec_sid) {
> + return SMMU_SEC_SID_NS;
> + }
> +
> + sec_sid = pdev->sec_sid;
> + if (!strcmp(sec_sid, "non-secure")) {
> + return SMMU_SEC_SID_NS;
> + }
> + if (!strcmp(sec_sid, "secure")) {
> + return SMMU_SEC_SID_S;
> + }
> +
> + error_report("Invalid sec-sid value '%s' for PCI device %02x:%02x.%x; "
> + "allowed values: non-secure or secure (case-sensitive)",
> + sec_sid, bus_num, PCI_SLOT(devfn), PCI_FUNC(devfn));
> + exit(EXIT_FAILURE);
> +}
> +
> void smmu_init_sdev(SMMUState *s, SMMUDevice *sdev, PCIBus *bus, int devfn)
> {
> static unsigned int index;
> g_autofree char *name = g_strdup_printf("%s-%d-%d", s->mrtypename, devfn,
> index++);
> + SMMUBaseClass *sbc = ARM_SMMU_GET_CLASS(s);
> + PCIDevice *pdev;
> + int bus_num;
> +
> sdev->smmu = s;
> sdev->bus = bus;
> sdev->devfn = devfn;
> + sdev->sec_sid = SMMU_SEC_SID_NS;
> +
> + bus_num = pci_bus_num(bus);
> + pdev = pci_find_device(bus, bus_num, devfn);
> + sdev->sec_sid = smmu_parse_pci_sec_sid(pdev, bus_num, devfn);
> + if (sbc->validate_sec_sid &&
> + !sbc->validate_sec_sid(s, sdev, bus_num)) {
> + exit(EXIT_FAILURE);
> + }
>
> memory_region_init_iommu(&sdev->iommu, sizeof(sdev->iommu),
> s->mrtypename, OBJECT(s), name, UINT64_MAX);
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 0b8ea922851..57a063b5e5d 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1116,7 +1116,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
> SMMUv3State *s = sdev->smmu;
> uint32_t sid = smmu_get_sid(sdev);
> - SMMUSecSID sec_sid = SMMU_SEC_SID_NS;
> + SMMUSecSID sec_sid = sdev->sec_sid;
> SMMUv3RegBank *bank = smmuv3_bank(s, sec_sid);
> SMMUEventInfo event = {.type = SMMU_EVT_NONE,
> .sid = sid,
> @@ -1509,6 +1509,36 @@ static inline bool smmu_hw_secure_implemented(SMMUv3State *s)
> return FIELD_EX32(s->bank[SMMU_SEC_SID_S].idr[1], S_IDR1, SECURE_IMPL);
> }
>
> +static bool smmuv3_validate_sec_sid(SMMUState *bs, SMMUDevice *sdev,
> + int bus_num)
> +{
> + SMMUv3State *s = ARM_SMMUV3(bs);
> + bool secure_as_available = bs->secure_memory &&
> + bs->secure_memory_as.root != NULL;
> +
> + if (sdev->sec_sid != SMMU_SEC_SID_S) {
> + return true;
> + }
> +
> + if (!smmu_hw_secure_implemented(s)) {
> + error_report("Invalid sec-sid value 'secure' for PCI device "
> + "%02x:%02x.%x: S_IDR1.SECURE_IMPL is 0, so only "
> + "non-secure is allowed",
> + bus_num, PCI_SLOT(sdev->devfn), PCI_FUNC(sdev->devfn));
> + return false;
> + }
> +
> + if (!secure_as_available) {
> + error_report("Invalid sec-sid value 'secure' for PCI device "
> + "%02x:%02x.%x: secure-memory address space is not "
> + "configured",
> + bus_num, PCI_SLOT(sdev->devfn), PCI_FUNC(sdev->devfn));
> + return false;
> + }
> +
> + return true;
> +}
> +
> static int smmuv3_cmdq_consume(SMMUv3State *s, Error **errp, SMMUSecSID sec_sid)
> {
> SMMUState *bs = ARM_SMMU(s);
> @@ -2664,6 +2694,7 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
> DeviceClass *dc = DEVICE_CLASS(klass);
> ResettableClass *rc = RESETTABLE_CLASS(klass);
> SMMUv3Class *c = ARM_SMMUV3_CLASS(klass);
> + SMMUBaseClass *sbc = ARM_SMMU_CLASS(klass);
>
> dc->vmsd = &vmstate_smmuv3;
> resettable_class_set_parent_phases(rc, NULL, NULL, smmu_reset_exit,
> @@ -2673,6 +2704,7 @@ static void smmuv3_class_init(ObjectClass *klass, const void *data)
> device_class_set_props(dc, smmuv3_properties);
> dc->hotpluggable = false;
> dc->user_creatable = true;
> + sbc->validate_sec_sid = smmuv3_validate_sec_sid;
>
> object_class_property_set_description(klass, "accel",
> "Enable SMMUv3 accelerator support. Allows host SMMUv3 to be "
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index d05cf6ae53b..c74f66a1bb9 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -144,6 +144,7 @@ typedef struct SMMUDevice {
> void *smmu;
> PCIBus *bus;
> int devfn;
> + SMMUSecSID sec_sid;
> IOMMUMemoryRegion iommu;
> AddressSpace as;
> uint32_t cfg_cache_hits;
> @@ -204,6 +205,7 @@ struct SMMUBaseClass {
> /*< public >*/
>
> DeviceRealize parent_realize;
> + bool (*validate_sec_sid)(struct SMMUState *s, SMMUDevice *sdev, int bus_num);
>
> };
>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 29/31] hw/arm/smmuv3: Initialize the secure register bank
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (27 preceding siblings ...)
2026-02-21 10:19 ` [RFC v4 28/31] hw/arm/smmuv3: Select sec-sid from PCI property and validate SECURE_IMPL Tao Tang
@ 2026-02-21 10:19 ` Tao Tang
2026-02-25 22:13 ` Pierrick Bouvier
2026-02-21 10:19 ` [RFC v4 30/31] hw/arm/smmuv3: Add secure bank migration and secure-impl property Tao Tang
2026-02-21 10:19 ` [RFC v4 31/31] [NOT-MERGE] hw/arm/smmuv3: temporarily enable SEL2 bit and sone other features Tao Tang
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:19 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Initialize the secure register bank (SMMU_SEC_SID_S) with sane default
values during the SMMU's reset sequence.
This change ensures that key fields, such as the secure ID registers,
GBPA reset value, and queue entry sizes, are set to a known-good state.
The SECURE_IMPL attribute of the S_IDR1 register will be introduced
later via device properties.
This is a necessary step to prevent undefined behavior when secure SMMU
features are subsequently enabled and used by software.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 57a063b5e5d..f0fbc5fc96b 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -321,7 +321,12 @@ static void smmuv3_init_id_regs(SMMUv3State *s)
bk->idr[5] = FIELD_DP32(bk->idr[5], IDR5, GRAN4K, 1);
bk->idr[5] = FIELD_DP32(bk->idr[5], IDR5, GRAN16K, 1);
bk->idr[5] = FIELD_DP32(bk->idr[5], IDR5, GRAN64K, 1);
- s->aidr = 0x1;
+
+ /* Initialize Secure bank */
+ SMMUv3RegBank *sbk = smmuv3_bank(s, SMMU_SEC_SID_S);
+ memset(sbk->idr, 0, sizeof(sbk->idr));
+ sbk->idr[0] = FIELD_DP32(bk->idr[0], S_IDR0, STALL_MODEL, 1); /* No stall */
+ sbk->idr[1] = FIELD_DP32(sbk->idr[1], S_IDR1, S_SIDSIZE, SMMU_IDR1_SIDSIZE);
smmuv3_accel_idr_override(s);
}
@@ -347,6 +352,26 @@ static void smmuv3_reset(SMMUv3State *s)
bk->gerrorn = 0;
bk->gbpa = SMMU_GBPA_RESET_VAL;
+ SMMUv3RegBank *sbk = smmuv3_bank(s, SMMU_SEC_SID_S);
+
+ sbk->cmdq.base = deposit64(sbk->cmdq.base, 0, 5, SMMU_CMDQS);
+ sbk->cmdq.prod = 0;
+ sbk->cmdq.cons = 0;
+ sbk->cmdq.entry_size = sizeof(struct Cmd);
+ sbk->eventq.base = deposit64(sbk->eventq.base, 0, 5, SMMU_EVENTQS);
+ sbk->eventq.prod = 0;
+ sbk->eventq.cons = 0;
+ sbk->eventq.entry_size = sizeof(struct Evt);
+
+ sbk->features = 0;
+ sbk->sid_split = 0;
+ sbk->cr[0] = 0;
+ sbk->cr0ack = 0;
+ sbk->irq_ctrl = 0;
+ sbk->gerror = 0;
+ sbk->gerrorn = 0;
+ sbk->gbpa = SMMU_GBPA_RESET_VAL;
+
s->aidr = 0x1;
s->statusr = 0;
}
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 29/31] hw/arm/smmuv3: Initialize the secure register bank
2026-02-21 10:19 ` [RFC v4 29/31] hw/arm/smmuv3: Initialize the secure register bank Tao Tang
@ 2026-02-25 22:13 ` Pierrick Bouvier
0 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 22:13 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:19 AM, Tao Tang wrote:
> Initialize the secure register bank (SMMU_SEC_SID_S) with sane default
> values during the SMMU's reset sequence.
>
> This change ensures that key fields, such as the secure ID registers,
> GBPA reset value, and queue entry sizes, are set to a known-good state.
> The SECURE_IMPL attribute of the S_IDR1 register will be introduced
> later via device properties.
>
> This is a necessary step to prevent undefined behavior when secure SMMU
> features are subsequently enabled and used by software.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 27 ++++++++++++++++++++++++++-
> 1 file changed, 26 insertions(+), 1 deletion(-)
>
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 30/31] hw/arm/smmuv3: Add secure bank migration and secure-impl property
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (28 preceding siblings ...)
2026-02-21 10:19 ` [RFC v4 29/31] hw/arm/smmuv3: Initialize the secure register bank Tao Tang
@ 2026-02-21 10:19 ` Tao Tang
2026-02-25 22:20 ` Pierrick Bouvier
2026-02-21 10:19 ` [RFC v4 31/31] [NOT-MERGE] hw/arm/smmuv3: temporarily enable SEL2 bit and sone other features Tao Tang
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:19 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Add a secure-impl device property and advertise it through
S_IDR1.SECURE_IMPL.
Usage:
-global arm-smmuv3,secure-impl=true
Add the smmuv3/bank_s migration subsection for the secure register bank.
Serialize secure bank state including GBPA, IRQ config, stream table and
queue state.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 56 +++++++++++++++++++++++++++++++++++++++++
include/hw/arm/smmuv3.h | 2 ++
2 files changed, 58 insertions(+)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index f0fbc5fc96b..678cbd584e2 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -327,6 +327,7 @@ static void smmuv3_init_id_regs(SMMUv3State *s)
memset(sbk->idr, 0, sizeof(sbk->idr));
sbk->idr[0] = FIELD_DP32(bk->idr[0], S_IDR0, STALL_MODEL, 1); /* No stall */
sbk->idr[1] = FIELD_DP32(sbk->idr[1], S_IDR1, S_SIDSIZE, SMMU_IDR1_SIDSIZE);
+ sbk->idr[1] = FIELD_DP32(sbk->idr[1], S_IDR1, SECURE_IMPL, s->secure_impl);
smmuv3_accel_idr_override(s);
}
@@ -2632,6 +2633,54 @@ static const VMStateDescription vmstate_smmuv3_queue = {
},
};
+static const VMStateDescription vmstate_smmuv3_secure_bank = {
+ .name = "smmuv3_secure_bank",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_UINT32(features, SMMUv3RegBank),
+ VMSTATE_UINT8(sid_split, SMMUv3RegBank),
+ VMSTATE_UINT32_ARRAY(cr, SMMUv3RegBank, 3),
+ VMSTATE_UINT32(cr0ack, SMMUv3RegBank),
+ VMSTATE_UINT32(gbpa, SMMUv3RegBank),
+ VMSTATE_UINT32(irq_ctrl, SMMUv3RegBank),
+ VMSTATE_UINT32(gerror, SMMUv3RegBank),
+ VMSTATE_UINT32(gerrorn, SMMUv3RegBank),
+ VMSTATE_UINT64(gerror_irq_cfg0, SMMUv3RegBank),
+ VMSTATE_UINT32(gerror_irq_cfg1, SMMUv3RegBank),
+ VMSTATE_UINT32(gerror_irq_cfg2, SMMUv3RegBank),
+ VMSTATE_UINT64(strtab_base, SMMUv3RegBank),
+ VMSTATE_UINT32(strtab_base_cfg, SMMUv3RegBank),
+ VMSTATE_UINT64(eventq_irq_cfg0, SMMUv3RegBank),
+ VMSTATE_UINT32(eventq_irq_cfg1, SMMUv3RegBank),
+ VMSTATE_UINT32(eventq_irq_cfg2, SMMUv3RegBank),
+ VMSTATE_STRUCT(cmdq, SMMUv3RegBank, 0,
+ vmstate_smmuv3_queue, SMMUQueue),
+ VMSTATE_STRUCT(eventq, SMMUv3RegBank, 0,
+ vmstate_smmuv3_queue, SMMUQueue),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
+static bool smmuv3_secure_bank_needed(void *opaque)
+{
+ SMMUv3State *s = opaque;
+
+ return s->secure_impl;
+}
+
+static const VMStateDescription vmstate_smmuv3_bank_s = {
+ .name = "smmuv3/bank_s",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .needed = smmuv3_secure_bank_needed,
+ .fields = (const VMStateField[]) {
+ VMSTATE_STRUCT(bank[SMMU_SEC_SID_S], SMMUv3State, 0,
+ vmstate_smmuv3_secure_bank, SMMUv3RegBank),
+ VMSTATE_END_OF_LIST(),
+ },
+};
+
static bool smmuv3_gbpa_needed(void *opaque)
{
SMMUv3State *s = opaque;
@@ -2686,6 +2735,7 @@ static const VMStateDescription vmstate_smmuv3 = {
},
.subsections = (const VMStateDescription * const []) {
&vmstate_gbpa,
+ &vmstate_smmuv3_bank_s,
NULL
}
};
@@ -2707,6 +2757,12 @@ static const Property smmuv3_properties[] = {
DEFINE_PROP_BOOL("ats", SMMUv3State, ats, false),
DEFINE_PROP_UINT8("oas", SMMUv3State, oas, 44),
DEFINE_PROP_UINT8("ssidsize", SMMUv3State, ssidsize, 0),
+ /*
+ * SECURE_IMPL field in S_IDR1 register.
+ * Indicates whether secure state is implemented.
+ * Defaults to false (0)
+ */
+ DEFINE_PROP_BOOL("secure-impl", SMMUv3State, secure_impl, false),
};
static void smmuv3_instance_init(Object *obj)
diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
index d07bdfa1f27..79ce7c754c4 100644
--- a/include/hw/arm/smmuv3.h
+++ b/include/hw/arm/smmuv3.h
@@ -78,6 +78,8 @@ struct SMMUv3State {
bool ats;
uint8_t oas;
uint8_t ssidsize;
+
+ bool secure_impl;
};
typedef enum {
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 30/31] hw/arm/smmuv3: Add secure bank migration and secure-impl property
2026-02-21 10:19 ` [RFC v4 30/31] hw/arm/smmuv3: Add secure bank migration and secure-impl property Tao Tang
@ 2026-02-25 22:20 ` Pierrick Bouvier
2026-02-27 16:16 ` Tao Tang
0 siblings, 1 reply; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 22:20 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:19 AM, Tao Tang wrote:
> Add a secure-impl device property and advertise it through
> S_IDR1.SECURE_IMPL.
>
> Usage:
> -global arm-smmuv3,secure-impl=true
>
> Add the smmuv3/bank_s migration subsection for the secure register bank.
> Serialize secure bank state including GBPA, IRQ config, stream table and
> queue state.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 56 +++++++++++++++++++++++++++++++++++++++++
> include/hw/arm/smmuv3.h | 2 ++
> 2 files changed, 58 insertions(+)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index f0fbc5fc96b..678cbd584e2 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -327,6 +327,7 @@ static void smmuv3_init_id_regs(SMMUv3State *s)
> memset(sbk->idr, 0, sizeof(sbk->idr));
> sbk->idr[0] = FIELD_DP32(bk->idr[0], S_IDR0, STALL_MODEL, 1); /* No stall */
> sbk->idr[1] = FIELD_DP32(sbk->idr[1], S_IDR1, S_SIDSIZE, SMMU_IDR1_SIDSIZE);
> + sbk->idr[1] = FIELD_DP32(sbk->idr[1], S_IDR1, SECURE_IMPL, s->secure_impl);
> smmuv3_accel_idr_override(s);
> }
>
> @@ -2632,6 +2633,54 @@ static const VMStateDescription vmstate_smmuv3_queue = {
> },
> };
>
> +static const VMStateDescription vmstate_smmuv3_secure_bank = {
> + .name = "smmuv3_secure_bank",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .fields = (const VMStateField[]) {
> + VMSTATE_UINT32(features, SMMUv3RegBank),
> + VMSTATE_UINT8(sid_split, SMMUv3RegBank),
> + VMSTATE_UINT32_ARRAY(cr, SMMUv3RegBank, 3),
> + VMSTATE_UINT32(cr0ack, SMMUv3RegBank),
> + VMSTATE_UINT32(gbpa, SMMUv3RegBank),
> + VMSTATE_UINT32(irq_ctrl, SMMUv3RegBank),
> + VMSTATE_UINT32(gerror, SMMUv3RegBank),
> + VMSTATE_UINT32(gerrorn, SMMUv3RegBank),
> + VMSTATE_UINT64(gerror_irq_cfg0, SMMUv3RegBank),
> + VMSTATE_UINT32(gerror_irq_cfg1, SMMUv3RegBank),
> + VMSTATE_UINT32(gerror_irq_cfg2, SMMUv3RegBank),
> + VMSTATE_UINT64(strtab_base, SMMUv3RegBank),
> + VMSTATE_UINT32(strtab_base_cfg, SMMUv3RegBank),
> + VMSTATE_UINT64(eventq_irq_cfg0, SMMUv3RegBank),
> + VMSTATE_UINT32(eventq_irq_cfg1, SMMUv3RegBank),
> + VMSTATE_UINT32(eventq_irq_cfg2, SMMUv3RegBank),
> + VMSTATE_STRUCT(cmdq, SMMUv3RegBank, 0,
> + vmstate_smmuv3_queue, SMMUQueue),
> + VMSTATE_STRUCT(eventq, SMMUv3RegBank, 0,
> + vmstate_smmuv3_queue, SMMUQueue),
> + VMSTATE_END_OF_LIST(),
> + },
> +};
> +
> +static bool smmuv3_secure_bank_needed(void *opaque)
> +{
> + SMMUv3State *s = opaque;
> +
> + return s->secure_impl;
> +}
> +
> +static const VMStateDescription vmstate_smmuv3_bank_s = {
> + .name = "smmuv3/bank_s",
> + .version_id = 1,
> + .minimum_version_id = 1,
> + .needed = smmuv3_secure_bank_needed,
> + .fields = (const VMStateField[]) {
> + VMSTATE_STRUCT(bank[SMMU_SEC_SID_S], SMMUv3State, 0,
> + vmstate_smmuv3_secure_bank, SMMUv3RegBank),
> + VMSTATE_END_OF_LIST(),
> + },
> +};
> +
> static bool smmuv3_gbpa_needed(void *opaque)
> {
> SMMUv3State *s = opaque;
> @@ -2686,6 +2735,7 @@ static const VMStateDescription vmstate_smmuv3 = {
> },
> .subsections = (const VMStateDescription * const []) {
> &vmstate_gbpa,
> + &vmstate_smmuv3_bank_s,
> NULL
> }
> };
> @@ -2707,6 +2757,12 @@ static const Property smmuv3_properties[] = {
> DEFINE_PROP_BOOL("ats", SMMUv3State, ats, false),
> DEFINE_PROP_UINT8("oas", SMMUv3State, oas, 44),
> DEFINE_PROP_UINT8("ssidsize", SMMUv3State, ssidsize, 0),
> + /*
> + * SECURE_IMPL field in S_IDR1 register.
> + * Indicates whether secure state is implemented.
> + * Defaults to false (0)
> + */
> + DEFINE_PROP_BOOL("secure-impl", SMMUv3State, secure_impl, false),
> };
>
As mentioned before, should we enable it automatically in case
secure-memory address space is available at realize time?
> static void smmuv3_instance_init(Object *obj)
> diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
> index d07bdfa1f27..79ce7c754c4 100644
> --- a/include/hw/arm/smmuv3.h
> +++ b/include/hw/arm/smmuv3.h
> @@ -78,6 +78,8 @@ struct SMMUv3State {
> bool ats;
> uint8_t oas;
> uint8_t ssidsize;
> +
> + bool secure_impl;
> };
>
> typedef enum {
Otherwise, congrats for the great series!
Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 30/31] hw/arm/smmuv3: Add secure bank migration and secure-impl property
2026-02-25 22:20 ` Pierrick Bouvier
@ 2026-02-27 16:16 ` Tao Tang
2026-02-27 21:54 ` Pierrick Bouvier
0 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-27 16:16 UTC (permalink / raw)
To: Pierrick Bouvier, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
Hi Pierrick,
On 2026/2/26 06:20, Pierrick Bouvier wrote:
> On 2/21/26 2:19 AM, Tao Tang wrote:
>> Add a secure-impl device property and advertise it through
>> S_IDR1.SECURE_IMPL.
>>
>> Usage:
>> -global arm-smmuv3,secure-impl=true
>>
>> Add the smmuv3/bank_s migration subsection for the secure register bank.
>> Serialize secure bank state including GBPA, IRQ config, stream table and
>> queue state.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmuv3.c | 56 +++++++++++++++++++++++++++++++++++++++++
>> include/hw/arm/smmuv3.h | 2 ++
>> 2 files changed, 58 insertions(+)
>>
>> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
>> index f0fbc5fc96b..678cbd584e2 100644
>> --- a/hw/arm/smmuv3.c
>> +++ b/hw/arm/smmuv3.c
>> @@ -327,6 +327,7 @@ static void smmuv3_init_id_regs(SMMUv3State *s)
>> memset(sbk->idr, 0, sizeof(sbk->idr));
>> sbk->idr[0] = FIELD_DP32(bk->idr[0], S_IDR0, STALL_MODEL, 1);
>> /* No stall */
>> sbk->idr[1] = FIELD_DP32(sbk->idr[1], S_IDR1, S_SIDSIZE,
>> SMMU_IDR1_SIDSIZE);
>> + sbk->idr[1] = FIELD_DP32(sbk->idr[1], S_IDR1, SECURE_IMPL,
>> s->secure_impl);
>> smmuv3_accel_idr_override(s);
>> }
>> @@ -2632,6 +2633,54 @@ static const VMStateDescription
>> vmstate_smmuv3_queue = {
>> },
>> };
>> +static const VMStateDescription vmstate_smmuv3_secure_bank = {
>> + .name = "smmuv3_secure_bank",
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .fields = (const VMStateField[]) {
>> + VMSTATE_UINT32(features, SMMUv3RegBank),
>> + VMSTATE_UINT8(sid_split, SMMUv3RegBank),
>> + VMSTATE_UINT32_ARRAY(cr, SMMUv3RegBank, 3),
>> + VMSTATE_UINT32(cr0ack, SMMUv3RegBank),
>> + VMSTATE_UINT32(gbpa, SMMUv3RegBank),
>> + VMSTATE_UINT32(irq_ctrl, SMMUv3RegBank),
>> + VMSTATE_UINT32(gerror, SMMUv3RegBank),
>> + VMSTATE_UINT32(gerrorn, SMMUv3RegBank),
>> + VMSTATE_UINT64(gerror_irq_cfg0, SMMUv3RegBank),
>> + VMSTATE_UINT32(gerror_irq_cfg1, SMMUv3RegBank),
>> + VMSTATE_UINT32(gerror_irq_cfg2, SMMUv3RegBank),
>> + VMSTATE_UINT64(strtab_base, SMMUv3RegBank),
>> + VMSTATE_UINT32(strtab_base_cfg, SMMUv3RegBank),
>> + VMSTATE_UINT64(eventq_irq_cfg0, SMMUv3RegBank),
>> + VMSTATE_UINT32(eventq_irq_cfg1, SMMUv3RegBank),
>> + VMSTATE_UINT32(eventq_irq_cfg2, SMMUv3RegBank),
>> + VMSTATE_STRUCT(cmdq, SMMUv3RegBank, 0,
>> + vmstate_smmuv3_queue, SMMUQueue),
>> + VMSTATE_STRUCT(eventq, SMMUv3RegBank, 0,
>> + vmstate_smmuv3_queue, SMMUQueue),
>> + VMSTATE_END_OF_LIST(),
>> + },
>> +};
>> +
>> +static bool smmuv3_secure_bank_needed(void *opaque)
>> +{
>> + SMMUv3State *s = opaque;
>> +
>> + return s->secure_impl;
>> +}
>> +
>> +static const VMStateDescription vmstate_smmuv3_bank_s = {
>> + .name = "smmuv3/bank_s",
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .needed = smmuv3_secure_bank_needed,
>> + .fields = (const VMStateField[]) {
>> + VMSTATE_STRUCT(bank[SMMU_SEC_SID_S], SMMUv3State, 0,
>> + vmstate_smmuv3_secure_bank, SMMUv3RegBank),
>> + VMSTATE_END_OF_LIST(),
>> + },
>> +};
>> +
>> static bool smmuv3_gbpa_needed(void *opaque)
>> {
>> SMMUv3State *s = opaque;
>> @@ -2686,6 +2735,7 @@ static const VMStateDescription vmstate_smmuv3 = {
>> },
>> .subsections = (const VMStateDescription * const []) {
>> &vmstate_gbpa,
>> + &vmstate_smmuv3_bank_s,
>> NULL
>> }
>> };
>> @@ -2707,6 +2757,12 @@ static const Property smmuv3_properties[] = {
>> DEFINE_PROP_BOOL("ats", SMMUv3State, ats, false),
>> DEFINE_PROP_UINT8("oas", SMMUv3State, oas, 44),
>> DEFINE_PROP_UINT8("ssidsize", SMMUv3State, ssidsize, 0),
>> + /*
>> + * SECURE_IMPL field in S_IDR1 register.
>> + * Indicates whether secure state is implemented.
>> + * Defaults to false (0)
>> + */
>> + DEFINE_PROP_BOOL("secure-impl", SMMUv3State, secure_impl, false),
>> };
>>
>
> As mentioned before, should we enable it automatically in case
> secure-memory address space is available at realize time?
Let me take this opportunity to address the same concern you raised
across patches #07, #17, and #30 on the secure-impl vs secure-memory topic.
My initial intent was a demand-driven (lazy) validation model — i.e.
only validate Secure capability when a device actually declares
sec-sid=secure and we go through smmu_init_sdev() /
smmuv3_validate_sec_sid(). That avoids forcing Secure-related
configuration checks on machines that never exercise Secure DMA.
That said, I agree with your point that secure-impl=on without a
corresponding secure-memory link is an unconditional misconfiguration
and should fail fast at realize time. For v5 I’ll combine both approaches:
1) Realize-time inference + fail-fast
- If a secure-memory address space is wired at realize time, the SMMU
should “do the right thing out of the box” and enable Secure support
automatically.
- If Secure support ends up enabled (either explicitly or via
auto-inference) but secure-memory is missing, smmuv3_realize() will
error out with a clear message.
Importantly, I’ll preserve the explicit user override you mentioned
(-global arm-smmuv3.secure-impl=off).
2) Make helpers assume the invariant
With the realize-time invariant in place, the Secure branch in
smmu_get_address_space() will no longer “warn + return NULL”; it will
become an assert (or equivalent hard failure) because the machine
configuration is already validated.
3) Keep the device-level guard
I will keep smmuv3_validate_sec_sid() as a complementary per-device
guard. This still matters when the user forces secure-impl=off: if a
device declares sec-sid=secure, we can reject it immediately with a
targeted error at device init/hotplug time, which is a different
granularity than the SMMU-wide realize check.
I’ll incorporate these changes in the next revision.
>
>> static void smmuv3_instance_init(Object *obj)
>> diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
>> index d07bdfa1f27..79ce7c754c4 100644
>> --- a/include/hw/arm/smmuv3.h
>> +++ b/include/hw/arm/smmuv3.h
>> @@ -78,6 +78,8 @@ struct SMMUv3State {
>> bool ats;
>> uint8_t oas;
>> uint8_t ssidsize;
>> +
>> + bool secure_impl;
>> };
>> typedef enum {
>
> Otherwise, congrats for the great series!
Thanks for your time!
Tao
>
> Reviewed-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread* Re: [RFC v4 30/31] hw/arm/smmuv3: Add secure bank migration and secure-impl property
2026-02-27 16:16 ` Tao Tang
@ 2026-02-27 21:54 ` Pierrick Bouvier
0 siblings, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-27 21:54 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/27/26 8:16 AM, Tao Tang wrote:
>> As mentioned before, should we enable it automatically in case
>> secure-memory address space is available at realize time?
>
>
> Let me take this opportunity to address the same concern you raised
> across patches #07, #17, and #30 on the secure-impl vs secure-memory topic.
>
>
> My initial intent was a demand-driven (lazy) validation model — i.e.
> only validate Secure capability when a device actually declares
> sec-sid=secure and we go through smmu_init_sdev() /
> smmuv3_validate_sec_sid(). That avoids forcing Secure-related
> configuration checks on machines that never exercise Secure DMA.
>
> That said, I agree with your point that secure-impl=on without a
> corresponding secure-memory link is an unconditional misconfiguration
> and should fail fast at realize time. For v5 I’ll combine both approaches:
>
> 1) Realize-time inference + fail-fast
>
> - If a secure-memory address space is wired at realize time, the SMMU
> should “do the right thing out of the box” and enable Secure support
> automatically.
>
> - If Secure support ends up enabled (either explicitly or via
> auto-inference) but secure-memory is missing, smmuv3_realize() will
> error out with a clear message.
>
> Importantly, I’ll preserve the explicit user override you mentioned
> (-global arm-smmuv3.secure-impl=off).
>
This is a good summary.
Let's see what other people think about it, and if they are ok with it.
>
> 2) Make helpers assume the invariant
>
> With the realize-time invariant in place, the Secure branch in
> smmu_get_address_space() will no longer “warn + return NULL”; it will
> become an assert (or equivalent hard failure) because the machine
> configuration is already validated.
>
Sounds good.
>
> 3) Keep the device-level guard
>
> I will keep smmuv3_validate_sec_sid() as a complementary per-device
> guard. This still matters when the user forces secure-impl=off: if a
> device declares sec-sid=secure, we can reject it immediately with a
> targeted error at device init/hotplug time, which is a different
> granularity than the SMMU-wide realize check.
>
>
> I’ll incorporate these changes in the next revision.
>
Regards,
Pierrick
^ permalink raw reply [flat|nested] 136+ messages in thread
* [RFC v4 31/31] [NOT-MERGE] hw/arm/smmuv3: temporarily enable SEL2 bit and sone other features
2026-02-21 10:02 [RFC v4 00/31] hw/arm/smmuv3: Support Secure state for SMMUv3 Tao Tang
` (29 preceding siblings ...)
2026-02-21 10:19 ` [RFC v4 30/31] hw/arm/smmuv3: Add secure bank migration and secure-impl property Tao Tang
@ 2026-02-21 10:19 ` Tao Tang
2026-02-25 21:31 ` Pierrick Bouvier
30 siblings, 1 reply; 136+ messages in thread
From: Tao Tang @ 2026-02-21 10:19 UTC (permalink / raw)
To: Eric Auger, Peter Maydell, Michael S . Tsirkin, Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Pierrick Bouvier,
Philippe Mathieu-Daudé, Mostafa Saleh, Chao Liu, Tao Tang
Temporarily:
- enable S_IDR1.SEL2,
- change AIDR to 0x2 to indicate SMMUv3.2,
- use smaller SID size and Cmd/Evt queue size.
Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
---
hw/arm/smmuv3.c | 3 ++-
include/hw/arm/smmuv3-common.h | 6 +++---
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 678cbd584e2..332feb28787 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -328,6 +328,7 @@ static void smmuv3_init_id_regs(SMMUv3State *s)
sbk->idr[0] = FIELD_DP32(bk->idr[0], S_IDR0, STALL_MODEL, 1); /* No stall */
sbk->idr[1] = FIELD_DP32(sbk->idr[1], S_IDR1, S_SIDSIZE, SMMU_IDR1_SIDSIZE);
sbk->idr[1] = FIELD_DP32(sbk->idr[1], S_IDR1, SECURE_IMPL, s->secure_impl);
+ sbk->idr[1] = FIELD_DP32(sbk->idr[1], S_IDR1, SEL2, 1);
smmuv3_accel_idr_override(s);
}
@@ -373,7 +374,7 @@ static void smmuv3_reset(SMMUv3State *s)
sbk->gerrorn = 0;
sbk->gbpa = SMMU_GBPA_RESET_VAL;
- s->aidr = 0x1;
+ s->aidr = 0x2; /* SMMUv3.2 */
s->statusr = 0;
}
diff --git a/include/hw/arm/smmuv3-common.h b/include/hw/arm/smmuv3-common.h
index c40fa46fb88..57ce32aef7b 100644
--- a/include/hw/arm/smmuv3-common.h
+++ b/include/hw/arm/smmuv3-common.h
@@ -312,9 +312,9 @@ REG32(IDR1, 0x4)
FIELD(IDR1, ECMDQ, 31, 1)
#define SMMU_SSID_MAX_BITS 20
-#define SMMU_IDR1_SIDSIZE 16
-#define SMMU_CMDQS 19
-#define SMMU_EVENTQS 19
+#define SMMU_IDR1_SIDSIZE 6
+#define SMMU_CMDQS 10
+#define SMMU_EVENTQS 10
REG32(IDR2, 0x8)
FIELD(IDR2, BA_VATOS, 0, 10)
--
2.34.1
^ permalink raw reply related [flat|nested] 136+ messages in thread* Re: [RFC v4 31/31] [NOT-MERGE] hw/arm/smmuv3: temporarily enable SEL2 bit and sone other features
2026-02-21 10:19 ` [RFC v4 31/31] [NOT-MERGE] hw/arm/smmuv3: temporarily enable SEL2 bit and sone other features Tao Tang
@ 2026-02-25 21:31 ` Pierrick Bouvier
2026-02-25 22:07 ` Pierrick Bouvier
2026-02-27 16:13 ` Tao Tang
0 siblings, 2 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 21:31 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/21/26 2:19 AM, Tao Tang wrote:
> Temporarily:
> - enable S_IDR1.SEL2,
> - change AIDR to 0x2 to indicate SMMUv3.2,
> - use smaller SID size and Cmd/Evt queue size.
>
> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
> ---
> hw/arm/smmuv3.c | 3 ++-
> include/hw/arm/smmuv3-common.h | 6 +++---
> 2 files changed, 5 insertions(+), 4 deletions(-)
>
I have been able to boot hafnium with:
- instructions at
https://hnusdr.github.io/2025/08/09/Test-Secure-SMMU-with-Hafnium-ENG/
- the current patch
- qemu-system-aarch64 -global arm-smmuv3.secure-impl=on ...
In case someone else wants to reproduce this easily:
```
git clone https://github.com/p-b-o/qemu-linux-stack
cd qemu-linux-stack
git checkout optee-secure-smmu
./build.sh # only requires podman and qemu-user-static
./run.sh /path/to/qemu-system-aarch64
```
Tested-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 31/31] [NOT-MERGE] hw/arm/smmuv3: temporarily enable SEL2 bit and sone other features
2026-02-25 21:31 ` Pierrick Bouvier
@ 2026-02-25 22:07 ` Pierrick Bouvier
2026-02-27 16:13 ` Tao Tang
1 sibling, 0 replies; 136+ messages in thread
From: Pierrick Bouvier @ 2026-02-25 22:07 UTC (permalink / raw)
To: Tao Tang, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
On 2/25/26 1:31 PM, Pierrick Bouvier wrote:
> On 2/21/26 2:19 AM, Tao Tang wrote:
>> Temporarily:
>> - enable S_IDR1.SEL2,
>> - change AIDR to 0x2 to indicate SMMUv3.2,
>> - use smaller SID size and Cmd/Evt queue size.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmuv3.c | 3 ++-
>> include/hw/arm/smmuv3-common.h | 6 +++---
>> 2 files changed, 5 insertions(+), 4 deletions(-)
>>
>
> I have been able to boot hafnium with:
> - instructions at
> https://hnusdr.github.io/2025/08/09/Test-Secure-SMMU-with-Hafnium-ENG/
> - the current patch
> - qemu-system-aarch64 -global arm-smmuv3.secure-impl=on ...
>
> In case someone else wants to reproduce this easily:
>
> ```
> git clone https://github.com/p-b-o/qemu-linux-stack
> cd qemu-linux-stack
> git checkout optee-secure-smmu
> ./build.sh # only requires podman and qemu-user-static
> ./run.sh /path/to/qemu-system-aarch64
> ```
>
> Tested-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
If we could have a device access directly from optee, it could be used
to exercise secure translation as well.
However, I'm not really sure it's how optee is supposed to be used, and
it has very limited hardware support and abstractions.
^ permalink raw reply [flat|nested] 136+ messages in thread
* Re: [RFC v4 31/31] [NOT-MERGE] hw/arm/smmuv3: temporarily enable SEL2 bit and sone other features
2026-02-25 21:31 ` Pierrick Bouvier
2026-02-25 22:07 ` Pierrick Bouvier
@ 2026-02-27 16:13 ` Tao Tang
1 sibling, 0 replies; 136+ messages in thread
From: Tao Tang @ 2026-02-27 16:13 UTC (permalink / raw)
To: Pierrick Bouvier, Eric Auger, Peter Maydell, Michael S . Tsirkin,
Marcel Apfelbaum
Cc: qemu-devel, qemu-arm, Chen Baozi, Philippe Mathieu-Daudé,
Mostafa Saleh, Chao Liu
Hi Pierrick,
On 2026/2/26 05:31, Pierrick Bouvier wrote:
> On 2/21/26 2:19 AM, Tao Tang wrote:
>> Temporarily:
>> - enable S_IDR1.SEL2,
>> - change AIDR to 0x2 to indicate SMMUv3.2,
>> - use smaller SID size and Cmd/Evt queue size.
>>
>> Signed-off-by: Tao Tang <tangtao1634@phytium.com.cn>
>> ---
>> hw/arm/smmuv3.c | 3 ++-
>> include/hw/arm/smmuv3-common.h | 6 +++---
>> 2 files changed, 5 insertions(+), 4 deletions(-)
>>
>
> I have been able to boot hafnium with:
> - instructions at
> https://hnusdr.github.io/2025/08/09/Test-Secure-SMMU-with-Hafnium-ENG/
> - the current patch
> - qemu-system-aarch64 -global arm-smmuv3.secure-impl=on ...
>
> In case someone else wants to reproduce this easily:
>
> ```
> git clone https://github.com/p-b-o/qemu-linux-stack
> cd qemu-linux-stack
> git checkout optee-secure-smmu
> ./build.sh # only requires podman and qemu-user-static
> ./run.sh /path/to/qemu-system-aarch64
> ```
>
> Tested-by: Pierrick Bouvier <pierrick.bouvier@linaro.org>
Thanks for the test!
Hafnium is indeed a good way to exercise Secure register and Secure
command queue access.
Best regards,
Tao
^ permalink raw reply [flat|nested] 136+ messages in thread