* [RFC PATCH v3 01/18] hw/arm/smmu-common: Add missing size check for stage-1
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-13 11:30 ` Eric Auger
2024-04-29 3:23 ` [RFC PATCH v3 02/18] hw/arm/smmu: Fix IPA for stage-2 events Mostafa Saleh
` (18 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
According to the SMMU architecture specification (ARM IHI 0070 F.b),
in “3.4 Address sizes”
The address output from the translation causes a stage 1 Address Size
fault if it exceeds the range of the effective IPA size for the given CD.
However, this check was missing.
There is already a similar check for stage-2 against effective PA.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmu-common.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 1ce706bf94..eb2356bc35 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -381,6 +381,16 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
goto error;
}
+ /*
+ * The address output from the translation causes a stage 1 Address
+ * Size fault if it exceeds the range of the effective IPA size for
+ * the given CD.
+ */
+ if (gpa >= (1ULL << cfg->oas)) {
+ info->type = SMMU_PTW_ERR_ADDR_SIZE;
+ goto error;
+ }
+
tlbe->entry.translated_addr = gpa;
tlbe->entry.iova = iova & ~mask;
tlbe->entry.addr_mask = mask;
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 01/18] hw/arm/smmu-common: Add missing size check for stage-1
2024-04-29 3:23 ` [RFC PATCH v3 01/18] hw/arm/smmu-common: Add missing size check for stage-1 Mostafa Saleh
@ 2024-05-13 11:30 ` Eric Auger
0 siblings, 0 replies; 57+ messages in thread
From: Eric Auger @ 2024-05-13 11:30 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> According to the SMMU architecture specification (ARM IHI 0070 F.b),
> in “3.4 Address sizes”
> The address output from the translation causes a stage 1 Address Size
> fault if it exceeds the range of the effective IPA size for the given CD.
>
> However, this check was missing.
>
> There is already a similar check for stage-2 against effective PA.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
> ---
> hw/arm/smmu-common.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index 1ce706bf94..eb2356bc35 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -381,6 +381,16 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
> goto error;
> }
>
> + /*
> + * The address output from the translation causes a stage 1 Address
> + * Size fault if it exceeds the range of the effective IPA size for
> + * the given CD.
> + */
> + if (gpa >= (1ULL << cfg->oas)) {
> + info->type = SMMU_PTW_ERR_ADDR_SIZE;
> + goto error;
> + }
> +
> tlbe->entry.translated_addr = gpa;
> tlbe->entry.iova = iova & ~mask;
> tlbe->entry.addr_mask = mask;
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 02/18] hw/arm/smmu: Fix IPA for stage-2 events
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
2024-04-29 3:23 ` [RFC PATCH v3 01/18] hw/arm/smmu-common: Add missing size check for stage-1 Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-13 11:47 ` Eric Auger
2024-04-29 3:23 ` [RFC PATCH v3 03/18] hw/arm/smmuv3: Fix encoding of CLASS in events Mostafa Saleh
` (17 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
For the following events (ARM IHI 0070 F.b - 7.3 Event records):
- F_TRANSLATION
- F_ACCESS
- F_PERMISSION
- F_ADDR_SIZE
If fault occurs at stage 2, S2 == 1 and:
- If translating an IPA for a transaction (whether by input to
stage 2-only configuration, or after successful stage 1 translation),
CLASS == IN, and IPA is provided.
However, this was not implemented correctly, as for stage 2, we Qemu
only sets the S2 bit but not the IPA.
This field has the same bits as FetchAddr in F_WALK_EABT which is
populated correctly, so we don’t change that.
The population of this field should be done from the walker as the IPA address
wouldn't be known in case of nesting.
For stage 1, the spec says:
If fault occurs at stage 1, S2 == 0 and:
CLASS == IN, IPA is UNKNOWN.
So, no need to set it to for stage 1, as ptw_info is initialised by zero in
smmuv3_translate().
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmu-common.c | 10 ++++++----
hw/arm/smmuv3.c | 4 ++++
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index eb2356bc35..8a8c718e6b 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -448,7 +448,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
*/
if (ipa >= (1ULL << inputsize)) {
info->type = SMMU_PTW_ERR_TRANSLATION;
- goto error;
+ goto error_ipa;
}
while (level < VMSA_LEVELS) {
@@ -494,13 +494,13 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
*/
if (!PTE_AF(pte) && !cfg->s2cfg.affd) {
info->type = SMMU_PTW_ERR_ACCESS;
- goto error;
+ goto error_ipa;
}
s2ap = PTE_AP(pte);
if (is_permission_fault_s2(s2ap, perm)) {
info->type = SMMU_PTW_ERR_PERMISSION;
- goto error;
+ goto error_ipa;
}
/*
@@ -509,7 +509,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
*/
if (gpa >= (1ULL << cfg->s2cfg.eff_ps)) {
info->type = SMMU_PTW_ERR_ADDR_SIZE;
- goto error;
+ goto error_ipa;
}
tlbe->entry.translated_addr = gpa;
@@ -522,6 +522,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
}
info->type = SMMU_PTW_ERR_TRANSLATION;
+error_ipa:
+ info->addr = ipa;
error:
info->stage = 2;
tlbe->entry.perm = IOMMU_NONE;
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 2d1e0d55ec..9dd3ea48e4 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -949,6 +949,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
if (PTW_RECORD_FAULT(cfg)) {
event.type = SMMU_EVT_F_TRANSLATION;
event.u.f_translation.addr = addr;
+ event.u.f_translation.addr2 = ptw_info.addr;
event.u.f_translation.rnw = flag & 0x1;
}
break;
@@ -956,6 +957,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
if (PTW_RECORD_FAULT(cfg)) {
event.type = SMMU_EVT_F_ADDR_SIZE;
event.u.f_addr_size.addr = addr;
+ event.u.f_addr_size.addr2 = ptw_info.addr;
event.u.f_addr_size.rnw = flag & 0x1;
}
break;
@@ -963,6 +965,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
if (PTW_RECORD_FAULT(cfg)) {
event.type = SMMU_EVT_F_ACCESS;
event.u.f_access.addr = addr;
+ event.u.f_access.addr2 = ptw_info.addr;
event.u.f_access.rnw = flag & 0x1;
}
break;
@@ -970,6 +973,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
if (PTW_RECORD_FAULT(cfg)) {
event.type = SMMU_EVT_F_PERMISSION;
event.u.f_permission.addr = addr;
+ event.u.f_permission.addr2 = ptw_info.addr;
event.u.f_permission.rnw = flag & 0x1;
}
break;
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 02/18] hw/arm/smmu: Fix IPA for stage-2 events
2024-04-29 3:23 ` [RFC PATCH v3 02/18] hw/arm/smmu: Fix IPA for stage-2 events Mostafa Saleh
@ 2024-05-13 11:47 ` Eric Auger
2024-05-16 14:43 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-13 11:47 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> For the following events (ARM IHI 0070 F.b - 7.3 Event records):
> - F_TRANSLATION
> - F_ACCESS
> - F_PERMISSION
> - F_ADDR_SIZE
>
> If fault occurs at stage 2, S2 == 1 and:
> - If translating an IPA for a transaction (whether by input to
> stage 2-only configuration, or after successful stage 1 translation),
> CLASS == IN, and IPA is provided.
CLASS == IN sounds a bit confusing here since the class value depends on
what is being translated and class is not handled in that patch.
>
> However, this was not implemented correctly, as for stage 2, we Qemu
s/we QEMU/ the code
> only sets the S2 bit but not the IPA.
If this is a fix, please add the "Fixes:" tag and fixed commit sha1.
>
> This field has the same bits as FetchAddr in F_WALK_EABT which is
> populated correctly, so we don’t change that.
> The population of this field should be done from the walker as the IPA address
s/population/setting? I am not a native english speaker though
> wouldn't be known in case of nesting.
>
> For stage 1, the spec says:
> If fault occurs at stage 1, S2 == 0 and:
> CLASS == IN, IPA is UNKNOWN.
>
> So, no need to set it to for stage 1, as ptw_info is initialised by zero in
> smmuv3_translate().
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmu-common.c | 10 ++++++----
> hw/arm/smmuv3.c | 4 ++++
> 2 files changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index eb2356bc35..8a8c718e6b 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -448,7 +448,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> */
> if (ipa >= (1ULL << inputsize)) {
> info->type = SMMU_PTW_ERR_TRANSLATION;
> - goto error;
> + goto error_ipa;
> }
>
> while (level < VMSA_LEVELS) {
> @@ -494,13 +494,13 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> */
> if (!PTE_AF(pte) && !cfg->s2cfg.affd) {
> info->type = SMMU_PTW_ERR_ACCESS;
> - goto error;
> + goto error_ipa;
> }
>
> s2ap = PTE_AP(pte);
> if (is_permission_fault_s2(s2ap, perm)) {
> info->type = SMMU_PTW_ERR_PERMISSION;
> - goto error;
> + goto error_ipa;
> }
>
> /*
> @@ -509,7 +509,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> */
> if (gpa >= (1ULL << cfg->s2cfg.eff_ps)) {
> info->type = SMMU_PTW_ERR_ADDR_SIZE;
> - goto error;
> + goto error_ipa;
> }
>
> tlbe->entry.translated_addr = gpa;
> @@ -522,6 +522,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> }
> info->type = SMMU_PTW_ERR_TRANSLATION;
>
> +error_ipa:
> + info->addr = ipa;
> error:
> info->stage = 2;
> tlbe->entry.perm = IOMMU_NONE;
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 2d1e0d55ec..9dd3ea48e4 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -949,6 +949,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> if (PTW_RECORD_FAULT(cfg)) {
> event.type = SMMU_EVT_F_TRANSLATION;
> event.u.f_translation.addr = addr;
> + event.u.f_translation.addr2 = ptw_info.addr;
> event.u.f_translation.rnw = flag & 0x1;
> }
> break;
> @@ -956,6 +957,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> if (PTW_RECORD_FAULT(cfg)) {
> event.type = SMMU_EVT_F_ADDR_SIZE;
> event.u.f_addr_size.addr = addr;
> + event.u.f_addr_size.addr2 = ptw_info.addr;
> event.u.f_addr_size.rnw = flag & 0x1;
> }
> break;
> @@ -963,6 +965,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> if (PTW_RECORD_FAULT(cfg)) {
> event.type = SMMU_EVT_F_ACCESS;
> event.u.f_access.addr = addr;
> + event.u.f_access.addr2 = ptw_info.addr;
> event.u.f_access.rnw = flag & 0x1;
> }
> break;
> @@ -970,6 +973,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> if (PTW_RECORD_FAULT(cfg)) {
> event.type = SMMU_EVT_F_PERMISSION;
> event.u.f_permission.addr = addr;
> + event.u.f_permission.addr2 = ptw_info.addr;
> event.u.f_permission.rnw = flag & 0x1;
> }
> break;
>
After taking into account above comments,
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 02/18] hw/arm/smmu: Fix IPA for stage-2 events
2024-05-13 11:47 ` Eric Auger
@ 2024-05-16 14:43 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-05-16 14:43 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Mon, May 13, 2024 at 01:47:44PM +0200, Eric Auger wrote:
> Hi Mostafa,
>
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > For the following events (ARM IHI 0070 F.b - 7.3 Event records):
> > - F_TRANSLATION
> > - F_ACCESS
> > - F_PERMISSION
> > - F_ADDR_SIZE
> >
> > If fault occurs at stage 2, S2 == 1 and:
> > - If translating an IPA for a transaction (whether by input to
> > stage 2-only configuration, or after successful stage 1 translation),
> > CLASS == IN, and IPA is provided.
> CLASS == IN sounds a bit confusing here since the class value depends on
> what is being translated and class is not handled in that patch.
At this point only CLASS IN is used as nesting is not supported,
I will clarify that in the commit message.
> >
> > However, this was not implemented correctly, as for stage 2, we Qemu
> s/we QEMU/ the code
Will do.
> > only sets the S2 bit but not the IPA.
> If this is a fix, please add the "Fixes:" tag and fixed commit sha1.
Will do.
> >
> > This field has the same bits as FetchAddr in F_WALK_EABT which is
> > populated correctly, so we don’t change that.
> > The population of this field should be done from the walker as the IPA address
> s/population/setting? I am not a native english speaker though
Me neither :), I will change it.
Thanks,
Mostafa
> > wouldn't be known in case of nesting.
> >
> > For stage 1, the spec says:
> > If fault occurs at stage 1, S2 == 0 and:
> > CLASS == IN, IPA is UNKNOWN.
> >
> > So, no need to set it to for stage 1, as ptw_info is initialised by zero in
> > smmuv3_translate().
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmu-common.c | 10 ++++++----
> > hw/arm/smmuv3.c | 4 ++++
> > 2 files changed, 10 insertions(+), 4 deletions(-)
> >
> > diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> > index eb2356bc35..8a8c718e6b 100644
> > --- a/hw/arm/smmu-common.c
> > +++ b/hw/arm/smmu-common.c
> > @@ -448,7 +448,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> > */
> > if (ipa >= (1ULL << inputsize)) {
> > info->type = SMMU_PTW_ERR_TRANSLATION;
> > - goto error;
> > + goto error_ipa;
> > }
> >
> > while (level < VMSA_LEVELS) {
> > @@ -494,13 +494,13 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> > */
> > if (!PTE_AF(pte) && !cfg->s2cfg.affd) {
> > info->type = SMMU_PTW_ERR_ACCESS;
> > - goto error;
> > + goto error_ipa;
> > }
> >
> > s2ap = PTE_AP(pte);
> > if (is_permission_fault_s2(s2ap, perm)) {
> > info->type = SMMU_PTW_ERR_PERMISSION;
> > - goto error;
> > + goto error_ipa;
> > }
> >
> > /*
> > @@ -509,7 +509,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> > */
> > if (gpa >= (1ULL << cfg->s2cfg.eff_ps)) {
> > info->type = SMMU_PTW_ERR_ADDR_SIZE;
> > - goto error;
> > + goto error_ipa;
> > }
> >
> > tlbe->entry.translated_addr = gpa;
> > @@ -522,6 +522,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> > }
> > info->type = SMMU_PTW_ERR_TRANSLATION;
> >
> > +error_ipa:
> > + info->addr = ipa;
> > error:
> > info->stage = 2;
> > tlbe->entry.perm = IOMMU_NONE;
> > diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> > index 2d1e0d55ec..9dd3ea48e4 100644
> > --- a/hw/arm/smmuv3.c
> > +++ b/hw/arm/smmuv3.c
> > @@ -949,6 +949,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> > if (PTW_RECORD_FAULT(cfg)) {
> > event.type = SMMU_EVT_F_TRANSLATION;
> > event.u.f_translation.addr = addr;
> > + event.u.f_translation.addr2 = ptw_info.addr;
> > event.u.f_translation.rnw = flag & 0x1;
> > }
> > break;
> > @@ -956,6 +957,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> > if (PTW_RECORD_FAULT(cfg)) {
> > event.type = SMMU_EVT_F_ADDR_SIZE;
> > event.u.f_addr_size.addr = addr;
> > + event.u.f_addr_size.addr2 = ptw_info.addr;
> > event.u.f_addr_size.rnw = flag & 0x1;
> > }
> > break;
> > @@ -963,6 +965,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> > if (PTW_RECORD_FAULT(cfg)) {
> > event.type = SMMU_EVT_F_ACCESS;
> > event.u.f_access.addr = addr;
> > + event.u.f_access.addr2 = ptw_info.addr;
> > event.u.f_access.rnw = flag & 0x1;
> > }
> > break;
> > @@ -970,6 +973,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> > if (PTW_RECORD_FAULT(cfg)) {
> > event.type = SMMU_EVT_F_PERMISSION;
> > event.u.f_permission.addr = addr;
> > + event.u.f_permission.addr2 = ptw_info.addr;
> > event.u.f_permission.rnw = flag & 0x1;
> > }
> > break;
> >
> After taking into account above comments,
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>
> Eric
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 03/18] hw/arm/smmuv3: Fix encoding of CLASS in events
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
2024-04-29 3:23 ` [RFC PATCH v3 01/18] hw/arm/smmu-common: Add missing size check for stage-1 Mostafa Saleh
2024-04-29 3:23 ` [RFC PATCH v3 02/18] hw/arm/smmu: Fix IPA for stage-2 events Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-15 12:27 ` Eric Auger
2024-04-29 3:23 ` [RFC PATCH v3 04/18] hw/arm/smmu: Use enum for SMMU stage Mostafa Saleh
` (16 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
The SMMUv3 spec (ARM IHI 0070 F.b - 7.3 Event records) defines the
class of events faults as:
CLASS: The class of the operation that caused the fault:
- 0b00: CD, CD fetch.
- 0b01: TTD, Stage 1 translation table fetch.
- 0b10: IN, Input address
However, this value was not set and left as 0 which means CD and not
IN (0b10).
While at it, add an enum for class as it would be used for nesting.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmuv3-internal.h | 6 ++++++
hw/arm/smmuv3.c | 6 +++++-
2 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index e4dd11e1e6..0f3ecec804 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -32,6 +32,12 @@ typedef enum SMMUTranslationStatus {
SMMU_TRANS_SUCCESS,
} SMMUTranslationStatus;
+typedef enum SMMUTranslationClass {
+ SMMU_CLASS_CD,
+ SMMU_CLASS_TT,
+ SMMU_CLASS_IN,
+} SMMUTranslationClass;
+
/* MMIO Registers */
REG32(IDR0, 0x0)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 9dd3ea48e4..1eb5b160d2 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -942,7 +942,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
event.type = SMMU_EVT_F_WALK_EABT;
event.u.f_walk_eabt.addr = addr;
event.u.f_walk_eabt.rnw = flag & 0x1;
- event.u.f_walk_eabt.class = 0x1;
+ event.u.f_walk_eabt.class = SMMU_CLASS_TT;
event.u.f_walk_eabt.addr2 = ptw_info.addr;
break;
case SMMU_PTW_ERR_TRANSLATION:
@@ -950,6 +950,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
event.type = SMMU_EVT_F_TRANSLATION;
event.u.f_translation.addr = addr;
event.u.f_translation.addr2 = ptw_info.addr;
+ event.u.f_translation.class = SMMU_CLASS_IN;
event.u.f_translation.rnw = flag & 0x1;
}
break;
@@ -958,6 +959,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
event.type = SMMU_EVT_F_ADDR_SIZE;
event.u.f_addr_size.addr = addr;
event.u.f_addr_size.addr2 = ptw_info.addr;
+ event.u.f_translation.class = SMMU_CLASS_IN;
event.u.f_addr_size.rnw = flag & 0x1;
}
break;
@@ -966,6 +968,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
event.type = SMMU_EVT_F_ACCESS;
event.u.f_access.addr = addr;
event.u.f_access.addr2 = ptw_info.addr;
+ event.u.f_translation.class = SMMU_CLASS_IN;
event.u.f_access.rnw = flag & 0x1;
}
break;
@@ -974,6 +977,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
event.type = SMMU_EVT_F_PERMISSION;
event.u.f_permission.addr = addr;
event.u.f_permission.addr2 = ptw_info.addr;
+ event.u.f_translation.class = SMMU_CLASS_IN;
event.u.f_permission.rnw = flag & 0x1;
}
break;
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 03/18] hw/arm/smmuv3: Fix encoding of CLASS in events
2024-04-29 3:23 ` [RFC PATCH v3 03/18] hw/arm/smmuv3: Fix encoding of CLASS in events Mostafa Saleh
@ 2024-05-15 12:27 ` Eric Auger
2024-05-16 14:50 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-15 12:27 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> The SMMUv3 spec (ARM IHI 0070 F.b - 7.3 Event records) defines the
> class of events faults as:
>
> CLASS: The class of the operation that caused the fault:
> - 0b00: CD, CD fetch.
> - 0b01: TTD, Stage 1 translation table fetch.
> - 0b10: IN, Input address
>
> However, this value was not set and left as 0 which means CD and not
> IN (0b10).
> While at it, add an enum for class as it would be used for nesting.
If this fixes somethings please add a Fixes: tag.
Also you may add that until nested gets implemented, CLASS values are
the same for stage 1 and stage2. This will change later on.
Besides
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmuv3-internal.h | 6 ++++++
> hw/arm/smmuv3.c | 6 +++++-
> 2 files changed, 11 insertions(+), 1 deletion(-)
>
> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> index e4dd11e1e6..0f3ecec804 100644
> --- a/hw/arm/smmuv3-internal.h
> +++ b/hw/arm/smmuv3-internal.h
> @@ -32,6 +32,12 @@ typedef enum SMMUTranslationStatus {
> SMMU_TRANS_SUCCESS,
> } SMMUTranslationStatus;
>
> +typedef enum SMMUTranslationClass {
> + SMMU_CLASS_CD,
> + SMMU_CLASS_TT,
> + SMMU_CLASS_IN,
> +} SMMUTranslationClass;
> +
> /* MMIO Registers */
>
> REG32(IDR0, 0x0)
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 9dd3ea48e4..1eb5b160d2 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -942,7 +942,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> event.type = SMMU_EVT_F_WALK_EABT;
> event.u.f_walk_eabt.addr = addr;
> event.u.f_walk_eabt.rnw = flag & 0x1;
> - event.u.f_walk_eabt.class = 0x1;
> + event.u.f_walk_eabt.class = SMMU_CLASS_TT;
> event.u.f_walk_eabt.addr2 = ptw_info.addr;
> break;
> case SMMU_PTW_ERR_TRANSLATION:
> @@ -950,6 +950,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> event.type = SMMU_EVT_F_TRANSLATION;
> event.u.f_translation.addr = addr;
> event.u.f_translation.addr2 = ptw_info.addr;
> + event.u.f_translation.class = SMMU_CLASS_IN;
> event.u.f_translation.rnw = flag & 0x1;
> }
> break;
> @@ -958,6 +959,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> event.type = SMMU_EVT_F_ADDR_SIZE;
> event.u.f_addr_size.addr = addr;
> event.u.f_addr_size.addr2 = ptw_info.addr;
> + event.u.f_translation.class = SMMU_CLASS_IN;
> event.u.f_addr_size.rnw = flag & 0x1;
> }
> break;
> @@ -966,6 +968,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> event.type = SMMU_EVT_F_ACCESS;
> event.u.f_access.addr = addr;
> event.u.f_access.addr2 = ptw_info.addr;
> + event.u.f_translation.class = SMMU_CLASS_IN;
> event.u.f_access.rnw = flag & 0x1;
> }
> break;
> @@ -974,6 +977,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> event.type = SMMU_EVT_F_PERMISSION;
> event.u.f_permission.addr = addr;
> event.u.f_permission.addr2 = ptw_info.addr;
> + event.u.f_translation.class = SMMU_CLASS_IN;
> event.u.f_permission.rnw = flag & 0x1;
> }
> break;
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 03/18] hw/arm/smmuv3: Fix encoding of CLASS in events
2024-05-15 12:27 ` Eric Auger
@ 2024-05-16 14:50 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-05-16 14:50 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Wed, May 15, 2024 at 02:27:45PM +0200, Eric Auger wrote:
> Hi Mostafa,
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > The SMMUv3 spec (ARM IHI 0070 F.b - 7.3 Event records) defines the
> > class of events faults as:
> >
> > CLASS: The class of the operation that caused the fault:
> > - 0b00: CD, CD fetch.
> > - 0b01: TTD, Stage 1 translation table fetch.
> > - 0b10: IN, Input address
> >
> > However, this value was not set and left as 0 which means CD and not
> > IN (0b10).
> > While at it, add an enum for class as it would be used for nesting.
> If this fixes somethings please add a Fixes: tag.
>
> Also you may add that until nested gets implemented, CLASS values are
> the same for stage 1 and stage2. This will change later on.
Will do.
Thanks,
Mostafa
>
> Besides
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>
> Eric
>
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmuv3-internal.h | 6 ++++++
> > hw/arm/smmuv3.c | 6 +++++-
> > 2 files changed, 11 insertions(+), 1 deletion(-)
> >
> > diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> > index e4dd11e1e6..0f3ecec804 100644
> > --- a/hw/arm/smmuv3-internal.h
> > +++ b/hw/arm/smmuv3-internal.h
> > @@ -32,6 +32,12 @@ typedef enum SMMUTranslationStatus {
> > SMMU_TRANS_SUCCESS,
> > } SMMUTranslationStatus;
> >
> > +typedef enum SMMUTranslationClass {
> > + SMMU_CLASS_CD,
> > + SMMU_CLASS_TT,
> > + SMMU_CLASS_IN,
> > +} SMMUTranslationClass;
> > +
> > /* MMIO Registers */
> >
> > REG32(IDR0, 0x0)
> > diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> > index 9dd3ea48e4..1eb5b160d2 100644
> > --- a/hw/arm/smmuv3.c
> > +++ b/hw/arm/smmuv3.c
> > @@ -942,7 +942,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> > event.type = SMMU_EVT_F_WALK_EABT;
> > event.u.f_walk_eabt.addr = addr;
> > event.u.f_walk_eabt.rnw = flag & 0x1;
> > - event.u.f_walk_eabt.class = 0x1;
> > + event.u.f_walk_eabt.class = SMMU_CLASS_TT;
> > event.u.f_walk_eabt.addr2 = ptw_info.addr;
> > break;
> > case SMMU_PTW_ERR_TRANSLATION:
> > @@ -950,6 +950,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> > event.type = SMMU_EVT_F_TRANSLATION;
> > event.u.f_translation.addr = addr;
> > event.u.f_translation.addr2 = ptw_info.addr;
> > + event.u.f_translation.class = SMMU_CLASS_IN;
> > event.u.f_translation.rnw = flag & 0x1;
> > }
> > break;
> > @@ -958,6 +959,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> > event.type = SMMU_EVT_F_ADDR_SIZE;
> > event.u.f_addr_size.addr = addr;
> > event.u.f_addr_size.addr2 = ptw_info.addr;
> > + event.u.f_translation.class = SMMU_CLASS_IN;
> > event.u.f_addr_size.rnw = flag & 0x1;
> > }
> > break;
> > @@ -966,6 +968,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> > event.type = SMMU_EVT_F_ACCESS;
> > event.u.f_access.addr = addr;
> > event.u.f_access.addr2 = ptw_info.addr;
> > + event.u.f_translation.class = SMMU_CLASS_IN;
> > event.u.f_access.rnw = flag & 0x1;
> > }
> > break;
> > @@ -974,6 +977,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> > event.type = SMMU_EVT_F_PERMISSION;
> > event.u.f_permission.addr = addr;
> > event.u.f_permission.addr2 = ptw_info.addr;
> > + event.u.f_translation.class = SMMU_CLASS_IN;
> > event.u.f_permission.rnw = flag & 0x1;
> > }
> > break;
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 04/18] hw/arm/smmu: Use enum for SMMU stage
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (2 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 03/18] hw/arm/smmuv3: Fix encoding of CLASS in events Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-15 20:25 ` Alex Bennée
2024-04-29 3:23 ` [RFC PATCH v3 05/18] hw/arm/smmu: Split smmuv3_translate() Mostafa Saleh
` (15 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
Currently, translation stage is represented as an int, where 1 is stage-1 and
2 is stage-2, when nested is added, 3 would be confusing to represent nesting,
so we use an enum instead.
While keeping the same values, this is useful for:
- Doing tricks with bit masks, where BIT(0) is stage-1 and BIT(1) is
stage-2 and both is nested.
- Tracing, as stage is printed as int.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
hw/arm/smmu-common.c | 14 +++++++-------
hw/arm/smmuv3.c | 15 ++++++++-------
include/hw/arm/smmu-common.h | 11 +++++++++--
3 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 8a8c718e6b..8a5858f69f 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -304,7 +304,7 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
{
dma_addr_t baseaddr, indexmask;
- int stage = cfg->stage;
+ SMMUStage stage = cfg->stage;
SMMUTransTableInfo *tt = select_tt(cfg, iova);
uint8_t level, granule_sz, inputsize, stride;
@@ -402,7 +402,7 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
info->type = SMMU_PTW_ERR_TRANSLATION;
error:
- info->stage = 1;
+ info->stage = SMMU_STAGE_1;
tlbe->entry.perm = IOMMU_NONE;
return -EINVAL;
}
@@ -425,7 +425,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
dma_addr_t ipa, IOMMUAccessFlags perm,
SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
{
- const int stage = 2;
+ const SMMUStage stage = SMMU_STAGE_2;
int granule_sz = cfg->s2cfg.granule_sz;
/* ARM DDI0487I.a: Table D8-7. */
int inputsize = 64 - cfg->s2cfg.tsz;
@@ -525,7 +525,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
error_ipa:
info->addr = ipa;
error:
- info->stage = 2;
+ info->stage = SMMU_STAGE_2;
tlbe->entry.perm = IOMMU_NONE;
return -EINVAL;
}
@@ -544,9 +544,9 @@ error:
int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
{
- if (cfg->stage == 1) {
+ if (cfg->stage == SMMU_STAGE_1) {
return smmu_ptw_64_s1(cfg, iova, perm, tlbe, info);
- } else if (cfg->stage == 2) {
+ } else if (cfg->stage == SMMU_STAGE_2) {
/*
* If bypassing stage 1(or unimplemented), the input address is passed
* directly to stage 2 as IPA. If the input address of a transaction
@@ -555,7 +555,7 @@ int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
*/
if (iova >= (1ULL << cfg->oas)) {
info->type = SMMU_PTW_ERR_ADDR_SIZE;
- info->stage = 1;
+ info->stage = SMMU_STAGE_1;
tlbe->entry.perm = IOMMU_NONE;
return -EINVAL;
}
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 1eb5b160d2..dab3ad2db9 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -34,7 +34,8 @@
#include "smmuv3-internal.h"
#include "smmu-internal.h"
-#define PTW_RECORD_FAULT(cfg) (((cfg)->stage == 1) ? (cfg)->record_faults : \
+#define PTW_RECORD_FAULT(cfg) (((cfg)->stage == SMMU_STAGE_1) ? \
+ (cfg)->record_faults : \
(cfg)->s2cfg.record_faults)
/**
@@ -402,7 +403,7 @@ static bool s2_pgtable_config_valid(uint8_t sl0, uint8_t t0sz, uint8_t gran)
static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
{
- cfg->stage = 2;
+ cfg->stage = SMMU_STAGE_2;
if (STE_S2AA64(ste) == 0x0) {
qemu_log_mask(LOG_UNIMP,
@@ -678,7 +679,7 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event)
/* we support only those at the moment */
cfg->aa64 = true;
- cfg->stage = 1;
+ cfg->stage = SMMU_STAGE_1;
cfg->oas = oas2bits(CD_IPS(cd));
cfg->oas = MIN(oas2bits(SMMU_IDR5_OAS), cfg->oas);
@@ -762,7 +763,7 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
return ret;
}
- if (cfg->aborted || cfg->bypassed || (cfg->stage == 2)) {
+ if (cfg->aborted || cfg->bypassed || (cfg->stage == SMMU_STAGE_2)) {
return 0;
}
@@ -882,7 +883,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
goto epilogue;
}
- if (cfg->stage == 1) {
+ if (cfg->stage == SMMU_STAGE_1) {
/* Select stage1 translation table. */
tt = select_tt(cfg, addr);
if (!tt) {
@@ -919,7 +920,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
* nesting is not supported. So it is sufficient to check the
* translation stage to know the TLB stage for now.
*/
- event.u.f_walk_eabt.s2 = (cfg->stage == 2);
+ event.u.f_walk_eabt.s2 = (cfg->stage == SMMU_STAGE_2);
if (PTW_RECORD_FAULT(cfg)) {
event.type = SMMU_EVT_F_PERMISSION;
event.u.f_permission.addr = addr;
@@ -935,7 +936,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
if (smmu_ptw(cfg, aligned_addr, flag, cached_entry, &ptw_info)) {
/* All faults from PTW has S2 field. */
- event.u.f_walk_eabt.s2 = (ptw_info.stage == 2);
+ event.u.f_walk_eabt.s2 = (ptw_info.stage == SMMU_STAGE_2);
g_free(cached_entry);
switch (ptw_info.type) {
case SMMU_PTW_ERR_WALK_EABT:
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index 5ec2e6c1a4..b3c881f0ee 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -49,8 +49,15 @@ typedef enum {
SMMU_PTW_ERR_PERMISSION, /* Permission fault */
} SMMUPTWEventType;
+/* SMMU Stage */
+typedef enum {
+ SMMU_STAGE_1 = 1,
+ SMMU_STAGE_2,
+ SMMU_NESTED,
+} SMMUStage;
+
typedef struct SMMUPTWEventInfo {
- int stage;
+ SMMUStage stage;
SMMUPTWEventType type;
dma_addr_t addr; /* fetched address that induced an abort, if any */
} SMMUPTWEventInfo;
@@ -88,7 +95,7 @@ typedef struct SMMUS2Cfg {
*/
typedef struct SMMUTransCfg {
/* Shared fields between stage-1 and stage-2. */
- int stage; /* translation stage */
+ SMMUStage stage; /* translation stage */
bool disabled; /* smmu is disabled */
bool bypassed; /* translation is bypassed */
bool aborted; /* translation is aborted */
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 04/18] hw/arm/smmu: Use enum for SMMU stage
2024-04-29 3:23 ` [RFC PATCH v3 04/18] hw/arm/smmu: Use enum for SMMU stage Mostafa Saleh
@ 2024-05-15 20:25 ` Alex Bennée
0 siblings, 0 replies; 57+ messages in thread
From: Alex Bennée @ 2024-05-15 20:25 UTC (permalink / raw)
To: Mostafa Saleh
Cc: qemu-arm, eric.auger, peter.maydell, qemu-devel, jean-philippe,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Mostafa Saleh <smostafa@google.com> writes:
> Currently, translation stage is represented as an int, where 1 is stage-1 and
> 2 is stage-2, when nested is added, 3 would be confusing to represent nesting,
> so we use an enum instead.
>
> While keeping the same values, this is useful for:
> - Doing tricks with bit masks, where BIT(0) is stage-1 and BIT(1) is
> stage-2 and both is nested.
> - Tracing, as stage is printed as int.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
--
Alex Bennée
Virtualisation Tech Lead @ Linaro
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 05/18] hw/arm/smmu: Split smmuv3_translate()
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (3 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 04/18] hw/arm/smmu: Use enum for SMMU stage Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-04-29 3:23 ` [RFC PATCH v3 06/18] hw/arm/smmu: Consolidate ASID and VMID types Mostafa Saleh
` (14 subsequent siblings)
19 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
smmuv3_translate() does everything from STE/CD parsing to TLB lookup
and PTW.
Soon, when nesting is supported, stage-1 data (tt, CD) needs to be
translated using stage-2.
Split smmuv3_translate() to 3 functions:
- smmu_translate(): in smmu-common.c, which does the TLB lookup, PTW,
TLB insertion, all the functions are already there, this just puts
them together.
This also simplifies the code as it consolidates event generation
in case of TLB lookup permission failure or in TT selection.
- smmuv3_do_translate(): in smmuv3.c, Calls smmu_translate() and does
the event population in case of errors.
- smmuv3_translate(), now calls smmuv3_do_translate() for
translation while the rest is the same.
Also, add stage in trace_smmuv3_translate_success()
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
hw/arm/smmu-common.c | 59 +++++++++++
hw/arm/smmuv3.c | 191 +++++++++++++----------------------
hw/arm/trace-events | 2 +-
include/hw/arm/smmu-common.h | 8 ++
4 files changed, 141 insertions(+), 119 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 8a5858f69f..d94db6b34f 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -566,6 +566,65 @@ int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
g_assert_not_reached();
}
+SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
+ IOMMUAccessFlags flag, SMMUPTWEventInfo *info)
+{
+ uint64_t page_mask, aligned_addr;
+ SMMUTLBEntry *cached_entry = NULL;
+ SMMUTransTableInfo *tt;
+ int status;
+
+ /*
+ * Combined attributes used for TLB lookup, as only one stage is supported,
+ * it will hold attributes based on the enabled stage.
+ */
+ SMMUTransTableInfo tt_combined;
+
+ if (cfg->stage == SMMU_STAGE_1) {
+ /* Select stage1 translation table. */
+ tt = select_tt(cfg, addr);
+ if (!tt) {
+ info->type = SMMU_PTW_ERR_TRANSLATION;
+ info->stage = SMMU_STAGE_1;
+ return NULL;
+ }
+ tt_combined.granule_sz = tt->granule_sz;
+ tt_combined.tsz = tt->tsz;
+
+ } else {
+ /* Stage2. */
+ tt_combined.granule_sz = cfg->s2cfg.granule_sz;
+ tt_combined.tsz = cfg->s2cfg.tsz;
+ }
+
+ /*
+ * TLB lookup looks for granule and input size for a translation stage,
+ * as only one stage is supported right now, choose the right values
+ * from the configuration.
+ */
+ page_mask = (1ULL << tt_combined.granule_sz) - 1;
+ aligned_addr = addr & ~page_mask;
+
+ cached_entry = smmu_iotlb_lookup(bs, cfg, &tt_combined, aligned_addr);
+ if (cached_entry) {
+ if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) {
+ info->type = SMMU_PTW_ERR_PERMISSION;
+ info->stage = cfg->stage;
+ return NULL;
+ }
+ return cached_entry;
+ }
+
+ cached_entry = g_new0(SMMUTLBEntry, 1);
+ status = smmu_ptw(cfg, aligned_addr, flag, cached_entry, info);
+ if (status) {
+ g_free(cached_entry);
+ return NULL;
+ }
+ smmu_iotlb_insert(bs, cfg, cached_entry);
+ return cached_entry;
+}
+
/**
* The bus number is used for lookup when SID based invalidation occurs.
* In that case we lazily populate the SMMUPciBus array from the bus hash
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index dab3ad2db9..f98c157221 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -827,6 +827,75 @@ static void smmuv3_flush_config(SMMUDevice *sdev)
g_hash_table_remove(bc->configs, sdev);
}
+/* Do translation with TLB lookup. */
+static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
+ SMMUTransCfg *cfg,
+ SMMUEventInfo *event,
+ IOMMUAccessFlags flag,
+ SMMUTLBEntry **out_entry)
+{
+ SMMUPTWEventInfo ptw_info = {};
+ SMMUState *bs = ARM_SMMU(s);
+ SMMUTLBEntry *cached_entry = NULL;
+
+ cached_entry = smmu_translate(bs, cfg, addr, flag, &ptw_info);
+ if (!cached_entry) {
+ /* All faults from PTW has S2 field. */
+ event->u.f_walk_eabt.s2 = (ptw_info.stage == SMMU_STAGE_2);
+ switch (ptw_info.type) {
+ case SMMU_PTW_ERR_WALK_EABT:
+ event->type = SMMU_EVT_F_WALK_EABT;
+ event->u.f_walk_eabt.addr = addr;
+ event->u.f_walk_eabt.rnw = flag & 0x1;
+ event->u.f_walk_eabt.class = SMMU_CLASS_TT;
+ event->u.f_walk_eabt.addr2 = ptw_info.addr;
+ break;
+ case SMMU_PTW_ERR_TRANSLATION:
+ if (PTW_RECORD_FAULT(cfg)) {
+ event->type = SMMU_EVT_F_TRANSLATION;
+ event->u.f_translation.addr = addr;
+ event->u.f_translation.addr2 = ptw_info.addr;
+ event->u.f_translation.class = SMMU_CLASS_IN;
+ event->u.f_translation.rnw = flag & 0x1;
+ }
+ break;
+ case SMMU_PTW_ERR_ADDR_SIZE:
+ if (PTW_RECORD_FAULT(cfg)) {
+ event->type = SMMU_EVT_F_ADDR_SIZE;
+ event->u.f_addr_size.addr = addr;
+ event->u.f_addr_size.addr2 = ptw_info.addr;
+ event->u.f_addr_size.class = SMMU_CLASS_IN;
+ event->u.f_addr_size.rnw = flag & 0x1;
+ }
+ break;
+ case SMMU_PTW_ERR_ACCESS:
+ if (PTW_RECORD_FAULT(cfg)) {
+ event->type = SMMU_EVT_F_ACCESS;
+ event->u.f_access.addr = addr;
+ event->u.f_access.addr2 = ptw_info.addr;
+ event->u.f_access.class = SMMU_CLASS_IN;
+ event->u.f_access.rnw = flag & 0x1;
+ }
+ break;
+ case SMMU_PTW_ERR_PERMISSION:
+ if (PTW_RECORD_FAULT(cfg)) {
+ event->type = SMMU_EVT_F_PERMISSION;
+ event->u.f_permission.addr = addr;
+ event->u.f_permission.addr2 = ptw_info.addr;
+ event->u.f_permission.class = SMMU_CLASS_IN;
+ event->u.f_permission.rnw = flag & 0x1;
+ }
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ return SMMU_TRANS_ERROR;
+ }
+ *out_entry = cached_entry;
+ return SMMU_TRANS_SUCCESS;
+}
+
+/* Entry point to SMMU, does everything. */
static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
IOMMUAccessFlags flag, int iommu_idx)
{
@@ -836,12 +905,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
SMMUEventInfo event = {.type = SMMU_EVT_NONE,
.sid = sid,
.inval_ste_allowed = false};
- SMMUPTWEventInfo ptw_info = {};
SMMUTranslationStatus status;
- SMMUState *bs = ARM_SMMU(s);
- uint64_t page_mask, aligned_addr;
- SMMUTLBEntry *cached_entry = NULL;
- SMMUTransTableInfo *tt;
SMMUTransCfg *cfg = NULL;
IOMMUTLBEntry entry = {
.target_as = &address_space_memory,
@@ -850,11 +914,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
.addr_mask = ~(hwaddr)0,
.perm = IOMMU_NONE,
};
- /*
- * Combined attributes used for TLB lookup, as only one stage is supported,
- * it will hold attributes based on the enabled stage.
- */
- SMMUTransTableInfo tt_combined;
+ SMMUTLBEntry *cached_entry = NULL;
qemu_mutex_lock(&s->mutex);
@@ -883,113 +943,7 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
goto epilogue;
}
- if (cfg->stage == SMMU_STAGE_1) {
- /* Select stage1 translation table. */
- tt = select_tt(cfg, addr);
- if (!tt) {
- if (cfg->record_faults) {
- event.type = SMMU_EVT_F_TRANSLATION;
- event.u.f_translation.addr = addr;
- event.u.f_translation.rnw = flag & 0x1;
- }
- status = SMMU_TRANS_ERROR;
- goto epilogue;
- }
- tt_combined.granule_sz = tt->granule_sz;
- tt_combined.tsz = tt->tsz;
-
- } else {
- /* Stage2. */
- tt_combined.granule_sz = cfg->s2cfg.granule_sz;
- tt_combined.tsz = cfg->s2cfg.tsz;
- }
- /*
- * TLB lookup looks for granule and input size for a translation stage,
- * as only one stage is supported right now, choose the right values
- * from the configuration.
- */
- page_mask = (1ULL << tt_combined.granule_sz) - 1;
- aligned_addr = addr & ~page_mask;
-
- cached_entry = smmu_iotlb_lookup(bs, cfg, &tt_combined, aligned_addr);
- if (cached_entry) {
- if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) {
- status = SMMU_TRANS_ERROR;
- /*
- * We know that the TLB only contains either stage-1 or stage-2 as
- * nesting is not supported. So it is sufficient to check the
- * translation stage to know the TLB stage for now.
- */
- event.u.f_walk_eabt.s2 = (cfg->stage == SMMU_STAGE_2);
- if (PTW_RECORD_FAULT(cfg)) {
- event.type = SMMU_EVT_F_PERMISSION;
- event.u.f_permission.addr = addr;
- event.u.f_permission.rnw = flag & 0x1;
- }
- } else {
- status = SMMU_TRANS_SUCCESS;
- }
- goto epilogue;
- }
-
- cached_entry = g_new0(SMMUTLBEntry, 1);
-
- if (smmu_ptw(cfg, aligned_addr, flag, cached_entry, &ptw_info)) {
- /* All faults from PTW has S2 field. */
- event.u.f_walk_eabt.s2 = (ptw_info.stage == SMMU_STAGE_2);
- g_free(cached_entry);
- switch (ptw_info.type) {
- case SMMU_PTW_ERR_WALK_EABT:
- event.type = SMMU_EVT_F_WALK_EABT;
- event.u.f_walk_eabt.addr = addr;
- event.u.f_walk_eabt.rnw = flag & 0x1;
- event.u.f_walk_eabt.class = SMMU_CLASS_TT;
- event.u.f_walk_eabt.addr2 = ptw_info.addr;
- break;
- case SMMU_PTW_ERR_TRANSLATION:
- if (PTW_RECORD_FAULT(cfg)) {
- event.type = SMMU_EVT_F_TRANSLATION;
- event.u.f_translation.addr = addr;
- event.u.f_translation.addr2 = ptw_info.addr;
- event.u.f_translation.class = SMMU_CLASS_IN;
- event.u.f_translation.rnw = flag & 0x1;
- }
- break;
- case SMMU_PTW_ERR_ADDR_SIZE:
- if (PTW_RECORD_FAULT(cfg)) {
- event.type = SMMU_EVT_F_ADDR_SIZE;
- event.u.f_addr_size.addr = addr;
- event.u.f_addr_size.addr2 = ptw_info.addr;
- event.u.f_translation.class = SMMU_CLASS_IN;
- event.u.f_addr_size.rnw = flag & 0x1;
- }
- break;
- case SMMU_PTW_ERR_ACCESS:
- if (PTW_RECORD_FAULT(cfg)) {
- event.type = SMMU_EVT_F_ACCESS;
- event.u.f_access.addr = addr;
- event.u.f_access.addr2 = ptw_info.addr;
- event.u.f_translation.class = SMMU_CLASS_IN;
- event.u.f_access.rnw = flag & 0x1;
- }
- break;
- case SMMU_PTW_ERR_PERMISSION:
- if (PTW_RECORD_FAULT(cfg)) {
- event.type = SMMU_EVT_F_PERMISSION;
- event.u.f_permission.addr = addr;
- event.u.f_permission.addr2 = ptw_info.addr;
- event.u.f_translation.class = SMMU_CLASS_IN;
- event.u.f_permission.rnw = flag & 0x1;
- }
- break;
- default:
- g_assert_not_reached();
- }
- status = SMMU_TRANS_ERROR;
- } else {
- smmu_iotlb_insert(bs, cfg, cached_entry);
- status = SMMU_TRANS_SUCCESS;
- }
+ status = smmuv3_do_translate(s, addr, cfg, &event, flag, &cached_entry);
epilogue:
qemu_mutex_unlock(&s->mutex);
@@ -1000,7 +954,8 @@ epilogue:
(addr & cached_entry->entry.addr_mask);
entry.addr_mask = cached_entry->entry.addr_mask;
trace_smmuv3_translate_success(mr->parent_obj.name, sid, addr,
- entry.translated_addr, entry.perm);
+ entry.translated_addr, entry.perm,
+ cfg->stage);
break;
case SMMU_TRANS_DISABLE:
entry.perm = flag;
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index f1a54a02df..cc12924a84 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -37,7 +37,7 @@ smmuv3_get_ste(uint64_t addr) "STE addr: 0x%"PRIx64
smmuv3_translate_disable(const char *n, uint16_t sid, uint64_t addr, bool is_write) "%s sid=0x%x bypass (smmu disabled) iova:0x%"PRIx64" is_write=%d"
smmuv3_translate_bypass(const char *n, uint16_t sid, uint64_t addr, bool is_write) "%s sid=0x%x STE bypass iova:0x%"PRIx64" is_write=%d"
smmuv3_translate_abort(const char *n, uint16_t sid, uint64_t addr, bool is_write) "%s sid=0x%x abort on iova:0x%"PRIx64" is_write=%d"
-smmuv3_translate_success(const char *n, uint16_t sid, uint64_t iova, uint64_t translated, int perm) "%s sid=0x%x iova=0x%"PRIx64" translated=0x%"PRIx64" perm=0x%x"
+smmuv3_translate_success(const char *n, uint16_t sid, uint64_t iova, uint64_t translated, int perm, int stage) "%s sid=0x%x iova=0x%"PRIx64" translated=0x%"PRIx64" perm=0x%x stage=%d"
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"
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index b3c881f0ee..5944735632 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -183,6 +183,14 @@ static inline uint16_t smmu_get_sid(SMMUDevice *sdev)
int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info);
+
+/*
+ * smmu_translate - Look for a translation in TLB, if not, do a PTW.
+ * Returns NULL on PTW error or incase of TLB permission errors.
+ */
+SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
+ IOMMUAccessFlags flag, SMMUPTWEventInfo *info);
+
/**
* select_tt - compute which translation table shall be used according to
* the input iova and translation config and return the TT specific info
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [RFC PATCH v3 06/18] hw/arm/smmu: Consolidate ASID and VMID types
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (4 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 05/18] hw/arm/smmu: Split smmuv3_translate() Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-15 12:41 ` Eric Auger
2024-04-29 3:23 ` [RFC PATCH v3 07/18] hw/arm/smmuv3: Translate CD and TT using stage-2 table Mostafa Saleh
` (13 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
ASID and VMID used to be uint16_t in the translation config, however,
in other contexts they can be int as -1 in case of TLB invalidation,
to represent all(don’t care).
When stage-2 was added asid was set to -1 in stage-2 and vmid to -1
in stage-1 configs. However, that meant they were set as (65536),
this was not an issue as nesting was not supported and no
commands/lookup targets both.
With nesting, it’s critical to get this right as translation must be
tagged correctly with ASID/VMID, and with ASID=-1 meaning stage-2.
Represent ASID/VMID everywhere as int.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmu-common.c | 10 +++++-----
hw/arm/smmuv3.c | 4 ++--
hw/arm/trace-events | 18 +++++++++---------
include/hw/arm/smmu-common.h | 14 +++++++-------
4 files changed, 23 insertions(+), 23 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index d94db6b34f..21982621c0 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -57,7 +57,7 @@ static gboolean smmu_iotlb_key_equal(gconstpointer v1, gconstpointer v2)
(k1->vmid == k2->vmid);
}
-SMMUIOTLBKey smmu_get_iotlb_key(uint16_t asid, uint16_t vmid, uint64_t iova,
+SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
uint8_t tg, uint8_t level)
{
SMMUIOTLBKey key = {.asid = asid, .vmid = vmid, .iova = iova,
@@ -130,7 +130,7 @@ void smmu_iotlb_inv_all(SMMUState *s)
static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
gpointer user_data)
{
- uint16_t asid = *(uint16_t *)user_data;
+ int asid = *(int *)user_data;
SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
return SMMU_IOTLB_ASID(*iotlb_key) == asid;
@@ -139,7 +139,7 @@ static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
gpointer user_data)
{
- uint16_t vmid = *(uint16_t *)user_data;
+ int vmid = *(int *)user_data;
SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
return SMMU_IOTLB_VMID(*iotlb_key) == vmid;
@@ -191,13 +191,13 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
&info);
}
-void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
+void smmu_iotlb_inv_asid(SMMUState *s, int asid)
{
trace_smmu_iotlb_inv_asid(asid);
g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
}
-void smmu_iotlb_inv_vmid(SMMUState *s, uint16_t vmid)
+void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
{
trace_smmu_iotlb_inv_vmid(vmid);
g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index f98c157221..cc61708160 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1243,7 +1243,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
}
case SMMU_CMD_TLBI_NH_ASID:
{
- uint16_t asid = CMD_ASID(&cmd);
+ int asid = CMD_ASID(&cmd);
if (!STAGE1_SUPPORTED(s)) {
cmd_error = SMMU_CERROR_ILL;
@@ -1276,7 +1276,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
break;
case SMMU_CMD_TLBI_S12_VMALL:
{
- uint16_t vmid = CMD_VMID(&cmd);
+ int vmid = CMD_VMID(&cmd);
if (!STAGE2_SUPPORTED(s)) {
cmd_error = SMMU_CERROR_ILL;
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index cc12924a84..09ccd39548 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -11,13 +11,13 @@ 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(uint16_t asid) "IOTLB invalidate asid=%d"
-smmu_iotlb_inv_vmid(uint16_t vmid) "IOTLB invalidate vmid=%d"
-smmu_iotlb_inv_iova(uint16_t asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
+smmu_iotlb_inv_asid(int asid) "IOTLB invalidate asid=%d"
+smmu_iotlb_inv_vmid(int vmid) "IOTLB invalidate vmid=%d"
+smmu_iotlb_inv_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
smmu_inv_notifiers_mr(const char *name) "iommu mr=%s"
-smmu_iotlb_lookup_hit(uint16_t asid, uint16_t vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
-smmu_iotlb_lookup_miss(uint16_t asid, uint16_t vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache MISS asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
-smmu_iotlb_insert(uint16_t asid, uint16_t vmid, uint64_t addr, uint8_t tg, uint8_t level) "IOTLB ++ asid=%d vmid=%d addr=0x%"PRIx64" tg=%d level=%d"
+smmu_iotlb_lookup_hit(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
+smmu_iotlb_lookup_miss(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache MISS asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
+smmu_iotlb_insert(int asid, int vmid, uint64_t addr, uint8_t tg, uint8_t level) "IOTLB ++ asid=%d vmid=%d addr=0x%"PRIx64" tg=%d level=%d"
# smmuv3.c
smmuv3_read_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"
@@ -48,12 +48,12 @@ smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t p
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) "vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d"
smmuv3_cmdq_tlbi_nh(void) ""
-smmuv3_cmdq_tlbi_nh_asid(uint16_t asid) "asid=%d"
-smmuv3_cmdq_tlbi_s12_vmid(uint16_t vmid) "vmid=%d"
+smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
+smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
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, uint16_t asid, uint16_t vmid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
+smmuv3_inv_notifiers_iova(const char *name, int asid, int vmid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
# strongarm.c
strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d"
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index 5944735632..96eb017e50 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -84,7 +84,7 @@ typedef struct SMMUS2Cfg {
bool record_faults; /* Record fault events (S2R) */
uint8_t granule_sz; /* Granule page shift (based on S2TG) */
uint8_t eff_ps; /* Effective PA output range (based on S2PS) */
- uint16_t vmid; /* Virtual Machine ID (S2VMID) */
+ int vmid; /* Virtual Machine ID (S2VMID) */
uint64_t vttb; /* Address of translation table base (S2TTB) */
} SMMUS2Cfg;
@@ -108,7 +108,7 @@ typedef struct SMMUTransCfg {
uint64_t ttb; /* TT base address */
uint8_t oas; /* output address width */
uint8_t tbi; /* Top Byte Ignore */
- uint16_t asid;
+ int asid;
SMMUTransTableInfo tt[2];
/* Used by stage-2 only. */
struct SMMUS2Cfg s2cfg;
@@ -132,8 +132,8 @@ typedef struct SMMUPciBus {
typedef struct SMMUIOTLBKey {
uint64_t iova;
- uint16_t asid;
- uint16_t vmid;
+ int asid;
+ int vmid;
uint8_t tg;
uint8_t level;
} SMMUIOTLBKey;
@@ -205,11 +205,11 @@ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid);
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(uint16_t asid, uint16_t vmid, uint64_t iova,
+SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
uint8_t tg, uint8_t level);
void smmu_iotlb_inv_all(SMMUState *s);
-void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid);
-void smmu_iotlb_inv_vmid(SMMUState *s, uint16_t vmid);
+void smmu_iotlb_inv_asid(SMMUState *s, int asid);
+void smmu_iotlb_inv_vmid(SMMUState *s, int vmid);
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);
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 06/18] hw/arm/smmu: Consolidate ASID and VMID types
2024-04-29 3:23 ` [RFC PATCH v3 06/18] hw/arm/smmu: Consolidate ASID and VMID types Mostafa Saleh
@ 2024-05-15 12:41 ` Eric Auger
2024-06-17 14:55 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-15 12:41 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> ASID and VMID used to be uint16_t in the translation config, however,
> in other contexts they can be int as -1 in case of TLB invalidation,
other contexts = TLB invalidation, right?
> to represent all(don’t care).
add space bewteen all and (.
> When stage-2 was added asid was set to -1 in stage-2 and vmid to -1
> in stage-1 configs. However, that meant they were set as (65536),
> this was not an issue as nesting was not supported and no
> commands/lookup targets both.
s/targets/uses
>
> With nesting, it’s critical to get this right as translation must be
> tagged correctly with ASID/VMID, and with ASID=-1 meaning stage-2.
> Represent ASID/VMID everywhere as int.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmu-common.c | 10 +++++-----
> hw/arm/smmuv3.c | 4 ++--
> hw/arm/trace-events | 18 +++++++++---------
> include/hw/arm/smmu-common.h | 14 +++++++-------
> 4 files changed, 23 insertions(+), 23 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index d94db6b34f..21982621c0 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -57,7 +57,7 @@ static gboolean smmu_iotlb_key_equal(gconstpointer v1, gconstpointer v2)
> (k1->vmid == k2->vmid);
> }
>
> -SMMUIOTLBKey smmu_get_iotlb_key(uint16_t asid, uint16_t vmid, uint64_t iova,
> +SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> uint8_t tg, uint8_t level)
> {
> SMMUIOTLBKey key = {.asid = asid, .vmid = vmid, .iova = iova,
> @@ -130,7 +130,7 @@ void smmu_iotlb_inv_all(SMMUState *s)
> static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
> gpointer user_data)
> {
> - uint16_t asid = *(uint16_t *)user_data;
> + int asid = *(int *)user_data;
> SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
>
> return SMMU_IOTLB_ASID(*iotlb_key) == asid;
> @@ -139,7 +139,7 @@ static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
> static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
> gpointer user_data)
> {
> - uint16_t vmid = *(uint16_t *)user_data;
> + int vmid = *(int *)user_data;
> SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
>
> return SMMU_IOTLB_VMID(*iotlb_key) == vmid;
> @@ -191,13 +191,13 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> &info);
> }
>
> -void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
> +void smmu_iotlb_inv_asid(SMMUState *s, int asid)
> {
> trace_smmu_iotlb_inv_asid(asid);
> g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
> }
>
> -void smmu_iotlb_inv_vmid(SMMUState *s, uint16_t vmid)
> +void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
> {
> trace_smmu_iotlb_inv_vmid(vmid);
> g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index f98c157221..cc61708160 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1243,7 +1243,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
> }
> case SMMU_CMD_TLBI_NH_ASID:
> {
> - uint16_t asid = CMD_ASID(&cmd);
> + int asid = CMD_ASID(&cmd);
>
> if (!STAGE1_SUPPORTED(s)) {
> cmd_error = SMMU_CERROR_ILL;
> @@ -1276,7 +1276,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
> break;
> case SMMU_CMD_TLBI_S12_VMALL:
> {
> - uint16_t vmid = CMD_VMID(&cmd);
> + int vmid = CMD_VMID(&cmd);
>
> if (!STAGE2_SUPPORTED(s)) {
> cmd_error = SMMU_CERROR_ILL;
> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> index cc12924a84..09ccd39548 100644
> --- a/hw/arm/trace-events
> +++ b/hw/arm/trace-events
> @@ -11,13 +11,13 @@ 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(uint16_t asid) "IOTLB invalidate asid=%d"
> -smmu_iotlb_inv_vmid(uint16_t vmid) "IOTLB invalidate vmid=%d"
> -smmu_iotlb_inv_iova(uint16_t asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
> +smmu_iotlb_inv_asid(int asid) "IOTLB invalidate asid=%d"
> +smmu_iotlb_inv_vmid(int vmid) "IOTLB invalidate vmid=%d"
> +smmu_iotlb_inv_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
> smmu_inv_notifiers_mr(const char *name) "iommu mr=%s"
> -smmu_iotlb_lookup_hit(uint16_t asid, uint16_t vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
> -smmu_iotlb_lookup_miss(uint16_t asid, uint16_t vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache MISS asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
> -smmu_iotlb_insert(uint16_t asid, uint16_t vmid, uint64_t addr, uint8_t tg, uint8_t level) "IOTLB ++ asid=%d vmid=%d addr=0x%"PRIx64" tg=%d level=%d"
> +smmu_iotlb_lookup_hit(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
> +smmu_iotlb_lookup_miss(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache MISS asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
> +smmu_iotlb_insert(int asid, int vmid, uint64_t addr, uint8_t tg, uint8_t level) "IOTLB ++ asid=%d vmid=%d addr=0x%"PRIx64" tg=%d level=%d"
>
> # smmuv3.c
> smmuv3_read_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"
> @@ -48,12 +48,12 @@ smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t p
> 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) "vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d"
> smmuv3_cmdq_tlbi_nh(void) ""
> -smmuv3_cmdq_tlbi_nh_asid(uint16_t asid) "asid=%d"
> -smmuv3_cmdq_tlbi_s12_vmid(uint16_t vmid) "vmid=%d"
> +smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
> +smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
> smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
> 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, uint16_t asid, uint16_t vmid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
> +smmuv3_inv_notifiers_iova(const char *name, int asid, int vmid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
>
> # strongarm.c
> strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d"
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index 5944735632..96eb017e50 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -84,7 +84,7 @@ typedef struct SMMUS2Cfg {
> bool record_faults; /* Record fault events (S2R) */
> uint8_t granule_sz; /* Granule page shift (based on S2TG) */
> uint8_t eff_ps; /* Effective PA output range (based on S2PS) */
> - uint16_t vmid; /* Virtual Machine ID (S2VMID) */
> + int vmid; /* Virtual Machine ID (S2VMID) */
> uint64_t vttb; /* Address of translation table base (S2TTB) */
> } SMMUS2Cfg;
>
> @@ -108,7 +108,7 @@ typedef struct SMMUTransCfg {
> uint64_t ttb; /* TT base address */
> uint8_t oas; /* output address width */
> uint8_t tbi; /* Top Byte Ignore */
> - uint16_t asid;
> + int asid;
> SMMUTransTableInfo tt[2];
> /* Used by stage-2 only. */
> struct SMMUS2Cfg s2cfg;
> @@ -132,8 +132,8 @@ typedef struct SMMUPciBus {
>
> typedef struct SMMUIOTLBKey {
> uint64_t iova;
> - uint16_t asid;
> - uint16_t vmid;
> + int asid;
> + int vmid;
> uint8_t tg;
> uint8_t level;
> } SMMUIOTLBKey;
> @@ -205,11 +205,11 @@ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid);
> 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(uint16_t asid, uint16_t vmid, uint64_t iova,
> +SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> uint8_t tg, uint8_t level);
> void smmu_iotlb_inv_all(SMMUState *s);
> -void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid);
> -void smmu_iotlb_inv_vmid(SMMUState *s, uint16_t vmid);
> +void smmu_iotlb_inv_asid(SMMUState *s, int asid);
> +void smmu_iotlb_inv_vmid(SMMUState *s, int vmid);
> 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);
>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 06/18] hw/arm/smmu: Consolidate ASID and VMID types
2024-05-15 12:41 ` Eric Auger
@ 2024-06-17 14:55 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-06-17 14:55 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
Sorry no updates for a while, I have been away for some time,
but I am now back to working on this.
On Wed, May 15, 2024 at 02:41:42PM +0200, Eric Auger wrote:
> Hi Mostafa,
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > ASID and VMID used to be uint16_t in the translation config, however,
> > in other contexts they can be int as -1 in case of TLB invalidation,
> other contexts = TLB invalidation, right?
Yes, although I was thinking this can be used for global entries lookup also
in case we would support it in the future.
Thanks,
Mostafa
> > to represent all(don’t care).
> add space bewteen all and (.
> > When stage-2 was added asid was set to -1 in stage-2 and vmid to -1
> > in stage-1 configs. However, that meant they were set as (65536),
> > this was not an issue as nesting was not supported and no
> > commands/lookup targets both.
> s/targets/uses
> >
> > With nesting, it’s critical to get this right as translation must be
> > tagged correctly with ASID/VMID, and with ASID=-1 meaning stage-2.
> > Represent ASID/VMID everywhere as int.
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmu-common.c | 10 +++++-----
> > hw/arm/smmuv3.c | 4 ++--
> > hw/arm/trace-events | 18 +++++++++---------
> > include/hw/arm/smmu-common.h | 14 +++++++-------
> > 4 files changed, 23 insertions(+), 23 deletions(-)
> >
> > diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> > index d94db6b34f..21982621c0 100644
> > --- a/hw/arm/smmu-common.c
> > +++ b/hw/arm/smmu-common.c
> > @@ -57,7 +57,7 @@ static gboolean smmu_iotlb_key_equal(gconstpointer v1, gconstpointer v2)
> > (k1->vmid == k2->vmid);
> > }
> >
> > -SMMUIOTLBKey smmu_get_iotlb_key(uint16_t asid, uint16_t vmid, uint64_t iova,
> > +SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> > uint8_t tg, uint8_t level)
> > {
> > SMMUIOTLBKey key = {.asid = asid, .vmid = vmid, .iova = iova,
> > @@ -130,7 +130,7 @@ void smmu_iotlb_inv_all(SMMUState *s)
> > static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
> > gpointer user_data)
> > {
> > - uint16_t asid = *(uint16_t *)user_data;
> > + int asid = *(int *)user_data;
> > SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
> >
> > return SMMU_IOTLB_ASID(*iotlb_key) == asid;
> > @@ -139,7 +139,7 @@ static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
> > static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
> > gpointer user_data)
> > {
> > - uint16_t vmid = *(uint16_t *)user_data;
> > + int vmid = *(int *)user_data;
> > SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
> >
> > return SMMU_IOTLB_VMID(*iotlb_key) == vmid;
> > @@ -191,13 +191,13 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> > &info);
> > }
> >
> > -void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid)
> > +void smmu_iotlb_inv_asid(SMMUState *s, int asid)
> > {
> > trace_smmu_iotlb_inv_asid(asid);
> > g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
> > }
> >
> > -void smmu_iotlb_inv_vmid(SMMUState *s, uint16_t vmid)
> > +void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
> > {
> > trace_smmu_iotlb_inv_vmid(vmid);
> > g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
> > diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> > index f98c157221..cc61708160 100644
> > --- a/hw/arm/smmuv3.c
> > +++ b/hw/arm/smmuv3.c
> > @@ -1243,7 +1243,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
> > }
> > case SMMU_CMD_TLBI_NH_ASID:
> > {
> > - uint16_t asid = CMD_ASID(&cmd);
> > + int asid = CMD_ASID(&cmd);
> >
> > if (!STAGE1_SUPPORTED(s)) {
> > cmd_error = SMMU_CERROR_ILL;
> > @@ -1276,7 +1276,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
> > break;
> > case SMMU_CMD_TLBI_S12_VMALL:
> > {
> > - uint16_t vmid = CMD_VMID(&cmd);
> > + int vmid = CMD_VMID(&cmd);
> >
> > if (!STAGE2_SUPPORTED(s)) {
> > cmd_error = SMMU_CERROR_ILL;
> > diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> > index cc12924a84..09ccd39548 100644
> > --- a/hw/arm/trace-events
> > +++ b/hw/arm/trace-events
> > @@ -11,13 +11,13 @@ 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(uint16_t asid) "IOTLB invalidate asid=%d"
> > -smmu_iotlb_inv_vmid(uint16_t vmid) "IOTLB invalidate vmid=%d"
> > -smmu_iotlb_inv_iova(uint16_t asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
> > +smmu_iotlb_inv_asid(int asid) "IOTLB invalidate asid=%d"
> > +smmu_iotlb_inv_vmid(int vmid) "IOTLB invalidate vmid=%d"
> > +smmu_iotlb_inv_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
> > smmu_inv_notifiers_mr(const char *name) "iommu mr=%s"
> > -smmu_iotlb_lookup_hit(uint16_t asid, uint16_t vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
> > -smmu_iotlb_lookup_miss(uint16_t asid, uint16_t vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache MISS asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
> > -smmu_iotlb_insert(uint16_t asid, uint16_t vmid, uint64_t addr, uint8_t tg, uint8_t level) "IOTLB ++ asid=%d vmid=%d addr=0x%"PRIx64" tg=%d level=%d"
> > +smmu_iotlb_lookup_hit(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
> > +smmu_iotlb_lookup_miss(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache MISS asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
> > +smmu_iotlb_insert(int asid, int vmid, uint64_t addr, uint8_t tg, uint8_t level) "IOTLB ++ asid=%d vmid=%d addr=0x%"PRIx64" tg=%d level=%d"
> >
> > # smmuv3.c
> > smmuv3_read_mmio(uint64_t addr, uint64_t val, unsigned size, uint32_t r) "addr: 0x%"PRIx64" val:0x%"PRIx64" size: 0x%x(%d)"
> > @@ -48,12 +48,12 @@ smmuv3_config_cache_hit(uint32_t sid, uint32_t hits, uint32_t misses, uint32_t p
> > 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) "vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%d"
> > smmuv3_cmdq_tlbi_nh(void) ""
> > -smmuv3_cmdq_tlbi_nh_asid(uint16_t asid) "asid=%d"
> > -smmuv3_cmdq_tlbi_s12_vmid(uint16_t vmid) "vmid=%d"
> > +smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
> > +smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
> > smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
> > 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, uint16_t asid, uint16_t vmid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
> > +smmuv3_inv_notifiers_iova(const char *name, int asid, int vmid, uint64_t iova, uint8_t tg, uint64_t num_pages) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
> >
> > # strongarm.c
> > strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d"
> > diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> > index 5944735632..96eb017e50 100644
> > --- a/include/hw/arm/smmu-common.h
> > +++ b/include/hw/arm/smmu-common.h
> > @@ -84,7 +84,7 @@ typedef struct SMMUS2Cfg {
> > bool record_faults; /* Record fault events (S2R) */
> > uint8_t granule_sz; /* Granule page shift (based on S2TG) */
> > uint8_t eff_ps; /* Effective PA output range (based on S2PS) */
> > - uint16_t vmid; /* Virtual Machine ID (S2VMID) */
> > + int vmid; /* Virtual Machine ID (S2VMID) */
> > uint64_t vttb; /* Address of translation table base (S2TTB) */
> > } SMMUS2Cfg;
> >
> > @@ -108,7 +108,7 @@ typedef struct SMMUTransCfg {
> > uint64_t ttb; /* TT base address */
> > uint8_t oas; /* output address width */
> > uint8_t tbi; /* Top Byte Ignore */
> > - uint16_t asid;
> > + int asid;
> > SMMUTransTableInfo tt[2];
> > /* Used by stage-2 only. */
> > struct SMMUS2Cfg s2cfg;
> > @@ -132,8 +132,8 @@ typedef struct SMMUPciBus {
> >
> > typedef struct SMMUIOTLBKey {
> > uint64_t iova;
> > - uint16_t asid;
> > - uint16_t vmid;
> > + int asid;
> > + int vmid;
> > uint8_t tg;
> > uint8_t level;
> > } SMMUIOTLBKey;
> > @@ -205,11 +205,11 @@ IOMMUMemoryRegion *smmu_iommu_mr(SMMUState *s, uint32_t sid);
> > 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(uint16_t asid, uint16_t vmid, uint64_t iova,
> > +SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> > uint8_t tg, uint8_t level);
> > void smmu_iotlb_inv_all(SMMUState *s);
> > -void smmu_iotlb_inv_asid(SMMUState *s, uint16_t asid);
> > -void smmu_iotlb_inv_vmid(SMMUState *s, uint16_t vmid);
> > +void smmu_iotlb_inv_asid(SMMUState *s, int asid);
> > +void smmu_iotlb_inv_vmid(SMMUState *s, int vmid);
> > 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);
> >
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>
> Eric
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 07/18] hw/arm/smmuv3: Translate CD and TT using stage-2 table
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (5 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 06/18] hw/arm/smmu: Consolidate ASID and VMID types Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-15 13:15 ` Eric Auger
2024-04-29 3:23 ` [RFC PATCH v3 08/18] hw/arm/smmu-common: Add support for nested TLB Mostafa Saleh
` (12 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
According to ARM SMMU architecture specification (ARM IHI 0070 F.b),
In "5.2 Stream Table Entry":
[51:6] S1ContextPtr
If Config[1] == 1 (stage 2 enabled), this pointer is an IPA translated by
stage 2 and the programmed value must be within the range of the IAS.
In "5.4.1 CD notes":
The translation table walks performed from TTB0 or TTB1 are always performed
in IPA space if stage 2 translations are enabled.
This patch implements translation of the S1 context descriptor pointer and
TTBx base addresses through the S2 stage (IPA -> PA)
smmuv3_do_translate() is updated to have one arg which is translation
class, this is useful for:
- Decide wether a translation is stage-2 only or use the STE config.
- Populate the class in case of faults, WALK_EABT is lefat as it as
it is always triggered from TT access so no need to use the input
class.
In case for stage-2 only translation, which only used in nesting, the
stage and asid are saved and restored before and after calling
smmu_translate().
Translating CD or TTBx can fail for the following reasons:
1) Large address size: This is described in
(3.4.3 Address sizes of SMMU-originated accesses)
- For CD ptr larger than IAS, for SMMUv3.1, it can trigger either
C_BAD_STE or Translation fault, we implement the latter as it
requires no extra code.
- For TTBx, if larger than the effective stage 1 output address size, it
triggers C_BAD_CD.
2) Faults from PTWs (7.3 Event records)
- F_ADDR_SIZE: large address size after first level causes stage 2 Address
Size fault (Also in 3.4.3 Address sizes of SMMU-originated accesses)
- F_PERMISSION: Same as an address translation. However, when
CLASS == CD, the access is implicitly Data and a read.
- F_ACCESS: Same as an address translation.
- F_TRANSLATION: Same as an address translation.
- F_WALK_EABT: Same as an address translation.
These are already implemented in the PTW logic, so no extra handling
required.
As, there is multiple locations where the address is calculated from
cached entry, a new macro is introduced CACHED_ENTRY_TO_ADDR.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmuv3.c | 76 ++++++++++++++++++++++++++++++------
include/hw/arm/smmu-common.h | 3 ++
2 files changed, 66 insertions(+), 13 deletions(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index cc61708160..cc61c82321 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -337,14 +337,33 @@ static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
}
+static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
+ SMMUTransCfg *cfg,
+ SMMUEventInfo *event,
+ IOMMUAccessFlags flag,
+ SMMUTLBEntry **out_entry,
+ SMMUTranslationClass class);
/* @ssid > 0 not supported yet */
-static int smmu_get_cd(SMMUv3State *s, STE *ste, uint32_t ssid,
- CD *buf, SMMUEventInfo *event)
+static int smmu_get_cd(SMMUv3State *s, STE *ste, SMMUTransCfg *cfg,
+ uint32_t ssid, CD *buf, SMMUEventInfo *event)
{
dma_addr_t addr = STE_CTXPTR(ste);
int ret, i;
+ SMMUTranslationStatus status;
+ SMMUTLBEntry *entry;
trace_smmuv3_get_cd(addr);
+
+ if (cfg->stage == SMMU_NESTED) {
+ status = smmuv3_do_translate(s, addr, cfg, event,
+ IOMMU_RO, &entry, SMMU_CLASS_CD);
+ if (status != SMMU_TRANS_SUCCESS) {
+ return -EINVAL;
+ }
+
+ addr = CACHED_ENTRY_TO_ADDR(entry, addr);
+ }
+
/* TODO: guarantee 64-bit single-copy atomicity */
ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf),
MEMTXATTRS_UNSPECIFIED);
@@ -659,10 +678,13 @@ static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
return 0;
}
-static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event)
+static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
+ CD *cd, SMMUEventInfo *event)
{
int ret = -EINVAL;
int i;
+ SMMUTranslationStatus status;
+ SMMUTLBEntry *entry;
if (!CD_VALID(cd) || !CD_AARCH64(cd)) {
goto bad_cd;
@@ -713,9 +735,21 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event)
tt->tsz = tsz;
tt->ttb = CD_TTB(cd, i);
+
if (tt->ttb & ~(MAKE_64BIT_MASK(0, cfg->oas))) {
goto bad_cd;
}
+
+ /* Translate the TTBx, from IPA to PA if nesting is enabled. */
+ if (cfg->stage == SMMU_NESTED) {
+ status = smmuv3_do_translate(s, tt->ttb, cfg, event, IOMMU_RO,
+ &entry, SMMU_CLASS_TT);
+ if (status != SMMU_TRANS_SUCCESS) {
+ return -EINVAL;
+ }
+ tt->ttb = CACHED_ENTRY_TO_ADDR(entry, tt->ttb);
+ }
+
tt->had = CD_HAD(cd, i);
trace_smmuv3_decode_cd_tt(i, tt->tsz, tt->ttb, tt->granule_sz, tt->had);
}
@@ -767,12 +801,12 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
return 0;
}
- ret = smmu_get_cd(s, &ste, 0 /* ssid */, &cd, event);
+ ret = smmu_get_cd(s, &ste, cfg, 0 /* ssid */, &cd, event);
if (ret) {
return ret;
}
- return decode_cd(cfg, &cd, event);
+ return decode_cd(s, cfg, &cd, event);
}
/**
@@ -832,13 +866,29 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
SMMUTransCfg *cfg,
SMMUEventInfo *event,
IOMMUAccessFlags flag,
- SMMUTLBEntry **out_entry)
+ SMMUTLBEntry **out_entry,
+ SMMUTranslationClass class)
{
SMMUPTWEventInfo ptw_info = {};
SMMUState *bs = ARM_SMMU(s);
SMMUTLBEntry *cached_entry = NULL;
+ int asid, stage;
+ bool S2_only = class != SMMU_CLASS_IN;
+
+ if (S2_only) {
+ asid = cfg->asid;
+ stage = cfg->stage;
+ cfg->asid = -1;
+ cfg->stage = SMMU_STAGE_2;
+ }
cached_entry = smmu_translate(bs, cfg, addr, flag, &ptw_info);
+
+ if (S2_only) {
+ cfg->asid = asid;
+ cfg->stage = stage;
+ }
+
if (!cached_entry) {
/* All faults from PTW has S2 field. */
event->u.f_walk_eabt.s2 = (ptw_info.stage == SMMU_STAGE_2);
@@ -855,7 +905,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
event->type = SMMU_EVT_F_TRANSLATION;
event->u.f_translation.addr = addr;
event->u.f_translation.addr2 = ptw_info.addr;
- event->u.f_translation.class = SMMU_CLASS_IN;
+ event->u.f_translation.class = class;
event->u.f_translation.rnw = flag & 0x1;
}
break;
@@ -864,7 +914,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
event->type = SMMU_EVT_F_ADDR_SIZE;
event->u.f_addr_size.addr = addr;
event->u.f_addr_size.addr2 = ptw_info.addr;
- event->u.f_addr_size.class = SMMU_CLASS_IN;
+ event->u.f_addr_size.class = class;
event->u.f_addr_size.rnw = flag & 0x1;
}
break;
@@ -873,7 +923,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
event->type = SMMU_EVT_F_ACCESS;
event->u.f_access.addr = addr;
event->u.f_access.addr2 = ptw_info.addr;
- event->u.f_access.class = SMMU_CLASS_IN;
+ event->u.f_access.class = class;
event->u.f_access.rnw = flag & 0x1;
}
break;
@@ -882,7 +932,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
event->type = SMMU_EVT_F_PERMISSION;
event->u.f_permission.addr = addr;
event->u.f_permission.addr2 = ptw_info.addr;
- event->u.f_permission.class = SMMU_CLASS_IN;
+ event->u.f_permission.class = class;
event->u.f_permission.rnw = flag & 0x1;
}
break;
@@ -943,15 +993,15 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
goto epilogue;
}
- status = smmuv3_do_translate(s, addr, cfg, &event, flag, &cached_entry);
+ status = smmuv3_do_translate(s, addr, cfg, &event, flag,
+ &cached_entry, SMMU_CLASS_IN);
epilogue:
qemu_mutex_unlock(&s->mutex);
switch (status) {
case SMMU_TRANS_SUCCESS:
entry.perm = cached_entry->entry.perm;
- entry.translated_addr = cached_entry->entry.translated_addr +
- (addr & cached_entry->entry.addr_mask);
+ 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,
entry.translated_addr, entry.perm,
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index 96eb017e50..09d3b9e734 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -37,6 +37,9 @@
#define VMSA_IDXMSK(isz, strd, lvl) ((1ULL << \
VMSA_BIT_LVL(isz, strd, lvl)) - 1)
+#define CACHED_ENTRY_TO_ADDR(ent, addr) (ent)->entry.translated_addr + \
+ ((addr) & (ent)->entry.addr_mask);
+
/*
* Page table walk error types
*/
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 07/18] hw/arm/smmuv3: Translate CD and TT using stage-2 table
2024-04-29 3:23 ` [RFC PATCH v3 07/18] hw/arm/smmuv3: Translate CD and TT using stage-2 table Mostafa Saleh
@ 2024-05-15 13:15 ` Eric Auger
2024-05-16 16:11 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-15 13:15 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> According to ARM SMMU architecture specification (ARM IHI 0070 F.b),
> In "5.2 Stream Table Entry":
> [51:6] S1ContextPtr
> If Config[1] == 1 (stage 2 enabled), this pointer is an IPA translated by
> stage 2 and the programmed value must be within the range of the IAS.
>
> In "5.4.1 CD notes":
> The translation table walks performed from TTB0 or TTB1 are always performed
> in IPA space if stage 2 translations are enabled.
>
> This patch implements translation of the S1 context descriptor pointer and
> TTBx base addresses through the S2 stage (IPA -> PA)
>
> smmuv3_do_translate() is updated to have one arg which is translation
> class, this is useful for:
s/for/to?
> - Decide wether a translation is stage-2 only or use the STE config.
> - Populate the class in case of faults, WALK_EABT is lefat as it as
left unchanged?
> it is always triggered from TT access so no need to use the input
> class.
>
> In case for stage-2 only translation, which only used in nesting, the
in case of S2 translation used in the contexted of a nested translation, ...
> stage and asid are saved and restored before and after calling
> smmu_translate().
>
> Translating CD or TTBx can fail for the following reasons:
> 1) Large address size: This is described in
> (3.4.3 Address sizes of SMMU-originated accesses)
> - For CD ptr larger than IAS, for SMMUv3.1, it can trigger either
> C_BAD_STE or Translation fault, we implement the latter as it
> requires no extra code.
> - For TTBx, if larger than the effective stage 1 output address size, it
> triggers C_BAD_CD.
>
> 2) Faults from PTWs (7.3 Event records)
> - F_ADDR_SIZE: large address size after first level causes stage 2 Address
> Size fault (Also in 3.4.3 Address sizes of SMMU-originated accesses)
> - F_PERMISSION: Same as an address translation. However, when
> CLASS == CD, the access is implicitly Data and a read.
> - F_ACCESS: Same as an address translation.
> - F_TRANSLATION: Same as an address translation.
> - F_WALK_EABT: Same as an address translation.
> These are already implemented in the PTW logic, so no extra handling
> required.
>
> As, there is multiple locations where the address is calculated from
> cached entry, a new macro is introduced CACHED_ENTRY_TO_ADDR.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmuv3.c | 76 ++++++++++++++++++++++++++++++------
> include/hw/arm/smmu-common.h | 3 ++
> 2 files changed, 66 insertions(+), 13 deletions(-)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index cc61708160..cc61c82321 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -337,14 +337,33 @@ static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
>
> }
>
> +static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> + SMMUTransCfg *cfg,
> + SMMUEventInfo *event,
> + IOMMUAccessFlags flag,
> + SMMUTLBEntry **out_entry,
> + SMMUTranslationClass class);
> /* @ssid > 0 not supported yet */
> -static int smmu_get_cd(SMMUv3State *s, STE *ste, uint32_t ssid,
> - CD *buf, SMMUEventInfo *event)
> +static int smmu_get_cd(SMMUv3State *s, STE *ste, SMMUTransCfg *cfg,
> + uint32_t ssid, CD *buf, SMMUEventInfo *event)
> {
> dma_addr_t addr = STE_CTXPTR(ste);
> int ret, i;
> + SMMUTranslationStatus status;
> + SMMUTLBEntry *entry;
>
> trace_smmuv3_get_cd(addr);
> +
> + if (cfg->stage == SMMU_NESTED) {
> + status = smmuv3_do_translate(s, addr, cfg, event,
> + IOMMU_RO, &entry, SMMU_CLASS_CD);
> + if (status != SMMU_TRANS_SUCCESS) {
So I guess you rely on event being populated by above CD S2 translate().
it does not need to be patched, correct?
May be worth a comment.
> + return -EINVAL;
> + }
> +
> + addr = CACHED_ENTRY_TO_ADDR(entry, addr);
> + }
> +
> /* TODO: guarantee 64-bit single-copy atomicity */
> ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf),
> MEMTXATTRS_UNSPECIFIED);
> @@ -659,10 +678,13 @@ static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
> return 0;
> }
>
> -static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event)
> +static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
> + CD *cd, SMMUEventInfo *event)
> {
> int ret = -EINVAL;
> int i;
> + SMMUTranslationStatus status;
> + SMMUTLBEntry *entry;
>
> if (!CD_VALID(cd) || !CD_AARCH64(cd)) {
> goto bad_cd;
> @@ -713,9 +735,21 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event)
>
> tt->tsz = tsz;
> tt->ttb = CD_TTB(cd, i);
> +
> if (tt->ttb & ~(MAKE_64BIT_MASK(0, cfg->oas))) {
> goto bad_cd;
> }
> +
> + /* Translate the TTBx, from IPA to PA if nesting is enabled. */
> + if (cfg->stage == SMMU_NESTED) {
> + status = smmuv3_do_translate(s, tt->ttb, cfg, event, IOMMU_RO,
> + &entry, SMMU_CLASS_TT);
> + if (status != SMMU_TRANS_SUCCESS) {
same here.
> + return -EINVAL;
> + }
> + tt->ttb = CACHED_ENTRY_TO_ADDR(entry, tt->ttb);
> + }
> +
> tt->had = CD_HAD(cd, i);
> trace_smmuv3_decode_cd_tt(i, tt->tsz, tt->ttb, tt->granule_sz, tt->had);
> }
> @@ -767,12 +801,12 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
> return 0;
> }
>
> - ret = smmu_get_cd(s, &ste, 0 /* ssid */, &cd, event);
> + ret = smmu_get_cd(s, &ste, cfg, 0 /* ssid */, &cd, event);
> if (ret) {
> return ret;
> }
>
> - return decode_cd(cfg, &cd, event);
> + return decode_cd(s, cfg, &cd, event);
> }
>
> /**
> @@ -832,13 +866,29 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> SMMUTransCfg *cfg,
> SMMUEventInfo *event,
> IOMMUAccessFlags flag,
> - SMMUTLBEntry **out_entry)
> + SMMUTLBEntry **out_entry,
> + SMMUTranslationClass class)
> {
> SMMUPTWEventInfo ptw_info = {};
> SMMUState *bs = ARM_SMMU(s);
> SMMUTLBEntry *cached_entry = NULL;
> + int asid, stage;
> + bool S2_only = class != SMMU_CLASS_IN;
> +
> + if (S2_only) {
Please add a comment explaining that class value is used to identify
S2-only forced translation in the context of a nested translation.
In that case we hackily override the original config to reach our goal
and then restore the original config.
That's pretty hacky. Let's see if any other reviewer has a better idea
;-) on my end I understand it and I can bear the trick :)
> + asid = cfg->asid;
> + stage = cfg->stage;
> + cfg->asid = -1;
> + cfg->stage = SMMU_STAGE_2;
> + }
>
> cached_entry = smmu_translate(bs, cfg, addr, flag, &ptw_info);
> +
> + if (S2_only) {
> + cfg->asid = asid;
> + cfg->stage = stage;
> + }
> +
> if (!cached_entry) {
> /* All faults from PTW has S2 field. */
> event->u.f_walk_eabt.s2 = (ptw_info.stage == SMMU_STAGE_2);
> @@ -855,7 +905,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> event->type = SMMU_EVT_F_TRANSLATION;
> event->u.f_translation.addr = addr;
> event->u.f_translation.addr2 = ptw_info.addr;
> - event->u.f_translation.class = SMMU_CLASS_IN;
> + event->u.f_translation.class = class;
> event->u.f_translation.rnw = flag & 0x1;
> }
> break;
> @@ -864,7 +914,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> event->type = SMMU_EVT_F_ADDR_SIZE;
> event->u.f_addr_size.addr = addr;
> event->u.f_addr_size.addr2 = ptw_info.addr;
> - event->u.f_addr_size.class = SMMU_CLASS_IN;
> + event->u.f_addr_size.class = class;
> event->u.f_addr_size.rnw = flag & 0x1;
> }
> break;
> @@ -873,7 +923,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> event->type = SMMU_EVT_F_ACCESS;
> event->u.f_access.addr = addr;
> event->u.f_access.addr2 = ptw_info.addr;
> - event->u.f_access.class = SMMU_CLASS_IN;
> + event->u.f_access.class = class;
> event->u.f_access.rnw = flag & 0x1;
> }
> break;
> @@ -882,7 +932,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> event->type = SMMU_EVT_F_PERMISSION;
> event->u.f_permission.addr = addr;
> event->u.f_permission.addr2 = ptw_info.addr;
> - event->u.f_permission.class = SMMU_CLASS_IN;
> + event->u.f_permission.class = class;
> event->u.f_permission.rnw = flag & 0x1;
> }
> break;
> @@ -943,15 +993,15 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> goto epilogue;
> }
>
> - status = smmuv3_do_translate(s, addr, cfg, &event, flag, &cached_entry);
> + status = smmuv3_do_translate(s, addr, cfg, &event, flag,
> + &cached_entry, SMMU_CLASS_IN);
>
> epilogue:
> qemu_mutex_unlock(&s->mutex);
> switch (status) {
> case SMMU_TRANS_SUCCESS:
> entry.perm = cached_entry->entry.perm;
> - entry.translated_addr = cached_entry->entry.translated_addr +
> - (addr & cached_entry->entry.addr_mask);
> + 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,
> entry.translated_addr, entry.perm,
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index 96eb017e50..09d3b9e734 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -37,6 +37,9 @@
> #define VMSA_IDXMSK(isz, strd, lvl) ((1ULL << \
> VMSA_BIT_LVL(isz, strd, lvl)) - 1)
>
> +#define CACHED_ENTRY_TO_ADDR(ent, addr) (ent)->entry.translated_addr + \
> + ((addr) & (ent)->entry.addr_mask);
> +
nit; this could be introduced in a separate patch since you have a
caller in smmuv3_translate(). This may help the reviewer to focus on the
most important class related changes.
Besides
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
> /*
> * Page table walk error types
> */
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 07/18] hw/arm/smmuv3: Translate CD and TT using stage-2 table
2024-05-15 13:15 ` Eric Auger
@ 2024-05-16 16:11 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-05-16 16:11 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Wed, May 15, 2024 at 03:15:02PM +0200, Eric Auger wrote:
> Hi Mostafa,
>
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > According to ARM SMMU architecture specification (ARM IHI 0070 F.b),
> > In "5.2 Stream Table Entry":
> > [51:6] S1ContextPtr
> > If Config[1] == 1 (stage 2 enabled), this pointer is an IPA translated by
> > stage 2 and the programmed value must be within the range of the IAS.
> >
> > In "5.4.1 CD notes":
> > The translation table walks performed from TTB0 or TTB1 are always performed
> > in IPA space if stage 2 translations are enabled.
> >
> > This patch implements translation of the S1 context descriptor pointer and
> > TTBx base addresses through the S2 stage (IPA -> PA)
> >
> > smmuv3_do_translate() is updated to have one arg which is translation
> > class, this is useful for:
> s/for/to?
Will do.
> > - Decide wether a translation is stage-2 only or use the STE config.
> > - Populate the class in case of faults, WALK_EABT is lefat as it as
> left unchanged?
Yup, that's a typo.
> > it is always triggered from TT access so no need to use the input
> > class.
> >
> > In case for stage-2 only translation, which only used in nesting, the
> in case of S2 translation used in the contexted of a nested translation, ...
Will do.
> > stage and asid are saved and restored before and after calling
> > smmu_translate().
> >
> > Translating CD or TTBx can fail for the following reasons:
> > 1) Large address size: This is described in
> > (3.4.3 Address sizes of SMMU-originated accesses)
> > - For CD ptr larger than IAS, for SMMUv3.1, it can trigger either
> > C_BAD_STE or Translation fault, we implement the latter as it
> > requires no extra code.
> > - For TTBx, if larger than the effective stage 1 output address size, it
> > triggers C_BAD_CD.
> >
> > 2) Faults from PTWs (7.3 Event records)
> > - F_ADDR_SIZE: large address size after first level causes stage 2 Address
> > Size fault (Also in 3.4.3 Address sizes of SMMU-originated accesses)
> > - F_PERMISSION: Same as an address translation. However, when
> > CLASS == CD, the access is implicitly Data and a read.
> > - F_ACCESS: Same as an address translation.
> > - F_TRANSLATION: Same as an address translation.
> > - F_WALK_EABT: Same as an address translation.
> > These are already implemented in the PTW logic, so no extra handling
> > required.
> >
> > As, there is multiple locations where the address is calculated from
> > cached entry, a new macro is introduced CACHED_ENTRY_TO_ADDR.
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmuv3.c | 76 ++++++++++++++++++++++++++++++------
> > include/hw/arm/smmu-common.h | 3 ++
> > 2 files changed, 66 insertions(+), 13 deletions(-)
> >
> > diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> > index cc61708160..cc61c82321 100644
> > --- a/hw/arm/smmuv3.c
> > +++ b/hw/arm/smmuv3.c
> > @@ -337,14 +337,33 @@ static int smmu_get_ste(SMMUv3State *s, dma_addr_t addr, STE *buf,
> >
> > }
> >
> > +static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> > + SMMUTransCfg *cfg,
> > + SMMUEventInfo *event,
> > + IOMMUAccessFlags flag,
> > + SMMUTLBEntry **out_entry,
> > + SMMUTranslationClass class);
> > /* @ssid > 0 not supported yet */
> > -static int smmu_get_cd(SMMUv3State *s, STE *ste, uint32_t ssid,
> > - CD *buf, SMMUEventInfo *event)
> > +static int smmu_get_cd(SMMUv3State *s, STE *ste, SMMUTransCfg *cfg,
> > + uint32_t ssid, CD *buf, SMMUEventInfo *event)
> > {
> > dma_addr_t addr = STE_CTXPTR(ste);
> > int ret, i;
> > + SMMUTranslationStatus status;
> > + SMMUTLBEntry *entry;
> >
> > trace_smmuv3_get_cd(addr);
> > +
> > + if (cfg->stage == SMMU_NESTED) {
> > + status = smmuv3_do_translate(s, addr, cfg, event,
> > + IOMMU_RO, &entry, SMMU_CLASS_CD);
> > + if (status != SMMU_TRANS_SUCCESS) {
> So I guess you rely on event being populated by above CD S2 translate().
> it does not need to be patched, correct?
> May be worth a comment.
Yes, only the class is different, I will add a comment.
> > + return -EINVAL;
> > + }
> > +
> > + addr = CACHED_ENTRY_TO_ADDR(entry, addr);
> > + }
> > +
> > /* TODO: guarantee 64-bit single-copy atomicity */
> > ret = dma_memory_read(&address_space_memory, addr, buf, sizeof(*buf),
> > MEMTXATTRS_UNSPECIFIED);
> > @@ -659,10 +678,13 @@ static int smmu_find_ste(SMMUv3State *s, uint32_t sid, STE *ste,
> > return 0;
> > }
> >
> > -static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event)
> > +static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
> > + CD *cd, SMMUEventInfo *event)
> > {
> > int ret = -EINVAL;
> > int i;
> > + SMMUTranslationStatus status;
> > + SMMUTLBEntry *entry;
> >
> > if (!CD_VALID(cd) || !CD_AARCH64(cd)) {
> > goto bad_cd;
> > @@ -713,9 +735,21 @@ static int decode_cd(SMMUTransCfg *cfg, CD *cd, SMMUEventInfo *event)
> >
> > tt->tsz = tsz;
> > tt->ttb = CD_TTB(cd, i);
> > +
> > if (tt->ttb & ~(MAKE_64BIT_MASK(0, cfg->oas))) {
> > goto bad_cd;
> > }
> > +
> > + /* Translate the TTBx, from IPA to PA if nesting is enabled. */
> > + if (cfg->stage == SMMU_NESTED) {
> > + status = smmuv3_do_translate(s, tt->ttb, cfg, event, IOMMU_RO,
> > + &entry, SMMU_CLASS_TT);
> > + if (status != SMMU_TRANS_SUCCESS) {
> same here.
> > + return -EINVAL;
> > + }
> > + tt->ttb = CACHED_ENTRY_TO_ADDR(entry, tt->ttb);
> > + }
> > +
> > tt->had = CD_HAD(cd, i);
> > trace_smmuv3_decode_cd_tt(i, tt->tsz, tt->ttb, tt->granule_sz, tt->had);
> > }
> > @@ -767,12 +801,12 @@ static int smmuv3_decode_config(IOMMUMemoryRegion *mr, SMMUTransCfg *cfg,
> > return 0;
> > }
> >
> > - ret = smmu_get_cd(s, &ste, 0 /* ssid */, &cd, event);
> > + ret = smmu_get_cd(s, &ste, cfg, 0 /* ssid */, &cd, event);
> > if (ret) {
> > return ret;
> > }
> >
> > - return decode_cd(cfg, &cd, event);
> > + return decode_cd(s, cfg, &cd, event);
> > }
> >
> > /**
> > @@ -832,13 +866,29 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> > SMMUTransCfg *cfg,
> > SMMUEventInfo *event,
> > IOMMUAccessFlags flag,
> > - SMMUTLBEntry **out_entry)
> > + SMMUTLBEntry **out_entry,
> > + SMMUTranslationClass class)
> > {
> > SMMUPTWEventInfo ptw_info = {};
> > SMMUState *bs = ARM_SMMU(s);
> > SMMUTLBEntry *cached_entry = NULL;
> > + int asid, stage;
> > + bool S2_only = class != SMMU_CLASS_IN;
> > +
> > + if (S2_only) {
> Please add a comment explaining that class value is used to identify
> S2-only forced translation in the context of a nested translation.
> In that case we hackily override the original config to reach our goal
> and then restore the original config.
> That's pretty hacky. Let's see if any other reviewer has a better idea
> ;-) on my end I understand it and I can bear the trick :)
>
Indeed, this is unclear, I will add a comment.
I thought about this case a lot, I found this to be the least intrusive
way while having tolerable readability, it'd be great if someone has a
better idea.
>
> > + asid = cfg->asid;
> > + stage = cfg->stage;
> > + cfg->asid = -1;
> > + cfg->stage = SMMU_STAGE_2;
> > + }
> >
> > cached_entry = smmu_translate(bs, cfg, addr, flag, &ptw_info);
> > +
> > + if (S2_only) {
> > + cfg->asid = asid;
> > + cfg->stage = stage;
> > + }
> > +
> > if (!cached_entry) {
> > /* All faults from PTW has S2 field. */
> > event->u.f_walk_eabt.s2 = (ptw_info.stage == SMMU_STAGE_2);
> > @@ -855,7 +905,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> > event->type = SMMU_EVT_F_TRANSLATION;
> > event->u.f_translation.addr = addr;
> > event->u.f_translation.addr2 = ptw_info.addr;
> > - event->u.f_translation.class = SMMU_CLASS_IN;
> > + event->u.f_translation.class = class;
> > event->u.f_translation.rnw = flag & 0x1;
> > }
> > break;
> > @@ -864,7 +914,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> > event->type = SMMU_EVT_F_ADDR_SIZE;
> > event->u.f_addr_size.addr = addr;
> > event->u.f_addr_size.addr2 = ptw_info.addr;
> > - event->u.f_addr_size.class = SMMU_CLASS_IN;
> > + event->u.f_addr_size.class = class;
> > event->u.f_addr_size.rnw = flag & 0x1;
> > }
> > break;
> > @@ -873,7 +923,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> > event->type = SMMU_EVT_F_ACCESS;
> > event->u.f_access.addr = addr;
> > event->u.f_access.addr2 = ptw_info.addr;
> > - event->u.f_access.class = SMMU_CLASS_IN;
> > + event->u.f_access.class = class;
> > event->u.f_access.rnw = flag & 0x1;
> > }
> > break;
> > @@ -882,7 +932,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> > event->type = SMMU_EVT_F_PERMISSION;
> > event->u.f_permission.addr = addr;
> > event->u.f_permission.addr2 = ptw_info.addr;
> > - event->u.f_permission.class = SMMU_CLASS_IN;
> > + event->u.f_permission.class = class;
> > event->u.f_permission.rnw = flag & 0x1;
> > }
> > break;
> > @@ -943,15 +993,15 @@ static IOMMUTLBEntry smmuv3_translate(IOMMUMemoryRegion *mr, hwaddr addr,
> > goto epilogue;
> > }
> >
> > - status = smmuv3_do_translate(s, addr, cfg, &event, flag, &cached_entry);
> > + status = smmuv3_do_translate(s, addr, cfg, &event, flag,
> > + &cached_entry, SMMU_CLASS_IN);
> >
> > epilogue:
> > qemu_mutex_unlock(&s->mutex);
> > switch (status) {
> > case SMMU_TRANS_SUCCESS:
> > entry.perm = cached_entry->entry.perm;
> > - entry.translated_addr = cached_entry->entry.translated_addr +
> > - (addr & cached_entry->entry.addr_mask);
> > + 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,
> > entry.translated_addr, entry.perm,
> > diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> > index 96eb017e50..09d3b9e734 100644
> > --- a/include/hw/arm/smmu-common.h
> > +++ b/include/hw/arm/smmu-common.h
> > @@ -37,6 +37,9 @@
> > #define VMSA_IDXMSK(isz, strd, lvl) ((1ULL << \
> > VMSA_BIT_LVL(isz, strd, lvl)) - 1)
> >
> > +#define CACHED_ENTRY_TO_ADDR(ent, addr) (ent)->entry.translated_addr + \
> > + ((addr) & (ent)->entry.addr_mask);
> > +
> nit; this could be introduced in a separate patch since you have a
> caller in smmuv3_translate(). This may help the reviewer to focus on the
> most important class related changes.
Sure, I can introduce a small patch before this one with this macro.
Thanks,
Mostafa
> Besides
> Reviewed-by: Eric Auger <eric.auger@redhat.com>
>
> Eric
>
> > /*
> > * Page table walk error types
> > */
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 08/18] hw/arm/smmu-common: Add support for nested TLB
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (6 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 07/18] hw/arm/smmuv3: Translate CD and TT using stage-2 table Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-15 13:48 ` Eric Auger
2024-04-29 3:23 ` [RFC PATCH v3 09/18] hw/arm/smmu-common: Rework TLB lookup for nesting Mostafa Saleh
` (11 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
This patch adds support for nested(combined) TLB entries.
The main function combine_tlb() is not used here but in the next
patches, but to simplify the patches it is introduced first.
Main changes:
1) New entry added in the TLB, parent_perm, for nested TLB, holds the
stage-2 permission, this can be used to know the origin of a
permission fault from a cached entry as caching the “and” of the
permissions loses this information.
SMMUPTWEventInfo is used to hold information about PTW faults so
the event can be populated, the value of stage (which maps to S2
in the event) used to be set based on the current stage for TLB
permission faults, however with the parent_perm, it is now set
based on which perm has the missing permission
When nesting is not enabled it has the same value as perm which
doesn't change the logic.
2) As combined TLB implementation is used, the combination logic
chooses:
- tg and level from the entry which has the smallest addr_mask.
- Based on that the iova that would be cached is recalculated.
- Translated_addr is chosen from stage-2.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmu-common.c | 32 ++++++++++++++++++++++++++++----
include/hw/arm/smmu-common.h | 1 +
2 files changed, 29 insertions(+), 4 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 21982621c0..0d6945fa54 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -394,7 +394,7 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
tlbe->entry.translated_addr = gpa;
tlbe->entry.iova = iova & ~mask;
tlbe->entry.addr_mask = mask;
- tlbe->entry.perm = PTE_AP_TO_PERM(ap);
+ tlbe->parent_perm = tlbe->entry.perm = PTE_AP_TO_PERM(ap);
tlbe->level = level;
tlbe->granule = granule_sz;
return 0;
@@ -515,7 +515,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
tlbe->entry.translated_addr = gpa;
tlbe->entry.iova = ipa & ~mask;
tlbe->entry.addr_mask = mask;
- tlbe->entry.perm = s2ap;
+ tlbe->parent_perm = tlbe->entry.perm = s2ap;
tlbe->level = level;
tlbe->granule = granule_sz;
return 0;
@@ -530,6 +530,27 @@ error:
return -EINVAL;
}
+/* combine 2 TLB entries and return in tlbe in nested config. */
+static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
+ SMMUTLBEntry *tlbe_s2,
+ dma_addr_t iova,
+ SMMUTransCfg *cfg)
+{
+ if (tlbe_s2->entry.addr_mask < tlbe->entry.addr_mask) {
+ tlbe->entry.addr_mask = tlbe_s2->entry.addr_mask;
+ tlbe->granule = tlbe_s2->granule;
+ tlbe->level = tlbe_s2->level;
+ }
+
+ tlbe->entry.translated_addr = CACHED_ENTRY_TO_ADDR(tlbe_s2,
+ tlbe->entry.translated_addr);
+
+ tlbe->entry.iova = iova & ~tlbe->entry.addr_mask;
+ /* parent_perm has s2 perm while perm has s1 perm. */
+ tlbe->parent_perm = tlbe_s2->entry.perm;
+ return;
+}
+
/**
* smmu_ptw - Walk the page tables for an IOVA, according to @cfg
*
@@ -607,9 +628,12 @@ SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
cached_entry = smmu_iotlb_lookup(bs, cfg, &tt_combined, aligned_addr);
if (cached_entry) {
- if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) {
+ if ((flag & IOMMU_WO) && !(cached_entry->entry.perm &
+ cached_entry->parent_perm & IOMMU_WO)) {
info->type = SMMU_PTW_ERR_PERMISSION;
- info->stage = cfg->stage;
+ info->stage = !(cached_entry->entry.perm & IOMMU_WO) ?
+ SMMU_STAGE_1 :
+ SMMU_STAGE_2;
return NULL;
}
return cached_entry;
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index 09d3b9e734..1db566d451 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -77,6 +77,7 @@ typedef struct SMMUTLBEntry {
IOMMUTLBEntry entry;
uint8_t level;
uint8_t granule;
+ IOMMUAccessFlags parent_perm;
} SMMUTLBEntry;
/* Stage-2 configuration. */
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 08/18] hw/arm/smmu-common: Add support for nested TLB
2024-04-29 3:23 ` [RFC PATCH v3 08/18] hw/arm/smmu-common: Add support for nested TLB Mostafa Saleh
@ 2024-05-15 13:48 ` Eric Auger
2024-05-16 15:20 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-15 13:48 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> This patch adds support for nested(combined) TLB entries.
space between nested and (.
> The main function combine_tlb() is not used here but in the next
> patches, but to simplify the patches it is introduced first.
>
> Main changes:
> 1) New entry added in the TLB, parent_perm, for nested TLB, holds the
s/entry/field, s/TLB/SMMUTLBEntry struct
> stage-2 permission, this can be used to know the origin of a
> permission fault from a cached entry as caching the “and” of the
> permissions loses this information.
>
> SMMUPTWEventInfo is used to hold information about PTW faults so
> the event can be populated, the value of stage (which maps to S2
> in the event) used to be set based on the current stage for TLB
I don't understand "(which maps to S2 in the event)". What do you mean?
This could be S1 or S2 depending on the active stage, no?
> permission faults, however with the parent_perm, it is now set
> based on which perm has the missing permission
>
> When nesting is not enabled it has the same value as perm which
> doesn't change the logic.
>
> 2) As combined TLB implementation is used, the combination logic
> chooses:
> - tg and level from the entry which has the smallest addr_mask.
tbh I am scared bout swapping s1/s2 tg and level. In smmu_iotlb_lookup()
I see tt->granule_sz being used which is s1 data. I mean it is not
obvious to me this is correct. Could you maybe give more explanations
detailing why/how this is guaranted to work.
Can you give additional details about what s1+s2 combinations were tested?
> - Based on that the iova that would be cached is recalculated.
> - Translated_addr is chosen from stage-2.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmu-common.c | 32 ++++++++++++++++++++++++++++----
> include/hw/arm/smmu-common.h | 1 +
> 2 files changed, 29 insertions(+), 4 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index 21982621c0..0d6945fa54 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -394,7 +394,7 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
> tlbe->entry.translated_addr = gpa;
> tlbe->entry.iova = iova & ~mask;
> tlbe->entry.addr_mask = mask;
> - tlbe->entry.perm = PTE_AP_TO_PERM(ap);
> + tlbe->parent_perm = tlbe->entry.perm = PTE_AP_TO_PERM(ap);
nit: I would prefer on separate lines.
> tlbe->level = level;
> tlbe->granule = granule_sz;
> return 0;
> @@ -515,7 +515,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> tlbe->entry.translated_addr = gpa;
> tlbe->entry.iova = ipa & ~mask;
> tlbe->entry.addr_mask = mask;
> - tlbe->entry.perm = s2ap;
> + tlbe->parent_perm = tlbe->entry.perm = s2ap;
> tlbe->level = level;
> tlbe->granule = granule_sz;
> return 0;
> @@ -530,6 +530,27 @@ error:
> return -EINVAL;
> }
>
> +/* combine 2 TLB entries and return in tlbe in nested config. */
suggestion: combine S1 and S2 TLB entries into a single entry. As a
result the S1 entry is overriden with combined data.
> +static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
> + SMMUTLBEntry *tlbe_s2,
> + dma_addr_t iova,
> + SMMUTransCfg *cfg)
> +{
> + if (tlbe_s2->entry.addr_mask < tlbe->entry.addr_mask) {
> + tlbe->entry.addr_mask = tlbe_s2->entry.addr_mask;
> + tlbe->granule = tlbe_s2->granule;
> + tlbe->level = tlbe_s2->level;
> + }
> +
> + tlbe->entry.translated_addr = CACHED_ENTRY_TO_ADDR(tlbe_s2,
> + tlbe->entry.translated_addr);
> +
> + tlbe->entry.iova = iova & ~tlbe->entry.addr_mask;
> + /* parent_perm has s2 perm while perm has s1 perm. */
suggestion: while perm keeps s1 perm.
> + tlbe->parent_perm = tlbe_s2->entry.perm;
> + return;
> +}
> +
> /**
> * smmu_ptw - Walk the page tables for an IOVA, according to @cfg
> *
> @@ -607,9 +628,12 @@ SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
>
> cached_entry = smmu_iotlb_lookup(bs, cfg, &tt_combined, aligned_addr);
> if (cached_entry) {
> - if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) {
> + if ((flag & IOMMU_WO) && !(cached_entry->entry.perm &
> + cached_entry->parent_perm & IOMMU_WO)) {
> info->type = SMMU_PTW_ERR_PERMISSION;
> - info->stage = cfg->stage;
> + info->stage = !(cached_entry->entry.perm & IOMMU_WO) ?
> + SMMU_STAGE_1 :
> + SMMU_STAGE_2;
> return NULL;
> }
> return cached_entry;
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index 09d3b9e734..1db566d451 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -77,6 +77,7 @@ typedef struct SMMUTLBEntry {
> IOMMUTLBEntry entry;
> uint8_t level;
> uint8_t granule;
> + IOMMUAccessFlags parent_perm;
> } SMMUTLBEntry;
>
> /* Stage-2 configuration. */
Thanks
Eric
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 08/18] hw/arm/smmu-common: Add support for nested TLB
2024-05-15 13:48 ` Eric Auger
@ 2024-05-16 15:20 ` Mostafa Saleh
2024-05-20 8:20 ` Eric Auger
0 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-05-16 15:20 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Wed, May 15, 2024 at 03:48:05PM +0200, Eric Auger wrote:
> Hi Mostafa,
>
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > This patch adds support for nested(combined) TLB entries.
> space between nested and (.
Will do.
> > The main function combine_tlb() is not used here but in the next
> > patches, but to simplify the patches it is introduced first.
> >
> > Main changes:
> > 1) New entry added in the TLB, parent_perm, for nested TLB, holds the
> s/entry/field, s/TLB/SMMUTLBEntry struct
Will do.
> > stage-2 permission, this can be used to know the origin of a
> > permission fault from a cached entry as caching the “and” of the
> > permissions loses this information.
> >
> > SMMUPTWEventInfo is used to hold information about PTW faults so
> > the event can be populated, the value of stage (which maps to S2
> > in the event) used to be set based on the current stage for TLB
> I don't understand "(which maps to S2 in the event)". What do you mean?
> This could be S1 or S2 depending on the active stage, no?
Not really, if the IPA size is larger than S2 input size, this is
considered stage-1 fault.
For TLB permission fault, yes, that is how it is decided.
However, with nesting, a permission fault from a cached entry can be
from a stage-1 or stage-2, that’s why we now cache both and not just
the combined permission, and the logic to set fault stage is modified
accordingly.
> > permission faults, however with the parent_perm, it is now set
> > based on which perm has the missing permission
> >
> > When nesting is not enabled it has the same value as perm which
> > doesn't change the logic.
> >
> > 2) As combined TLB implementation is used, the combination logic
> > chooses:
> > - tg and level from the entry which has the smallest addr_mask.
> tbh I am scared bout swapping s1/s2 tg and level. In smmu_iotlb_lookup()
> I see tt->granule_sz being used which is s1 data. I mean it is not
> obvious to me this is correct. Could you maybe give more explanations
> detailing why/how this is guaranted to work.
As you mentioned the next patch reworks the lookup logic, I can reorder
the 2 patches if that is better, please let me know what you think?
>
> Can you give additional details about what s1+s2 combinations were tested?
I tested with S1 and S2 4K pages
S1 level = 3 and S2 level = 3
S1 level = 2 and S2 level = 3
S1 level = 3 and S2 level = 2
S1 level = 1 and S2 level = 2
And also tested with with S1 64K granule and S2 4K.
> > - Based on that the iova that would be cached is recalculated.
> > - Translated_addr is chosen from stage-2.
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmu-common.c | 32 ++++++++++++++++++++++++++++----
> > include/hw/arm/smmu-common.h | 1 +
> > 2 files changed, 29 insertions(+), 4 deletions(-)
> >
> > diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> > index 21982621c0..0d6945fa54 100644
> > --- a/hw/arm/smmu-common.c
> > +++ b/hw/arm/smmu-common.c
> > @@ -394,7 +394,7 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
> > tlbe->entry.translated_addr = gpa;
> > tlbe->entry.iova = iova & ~mask;
> > tlbe->entry.addr_mask = mask;
> > - tlbe->entry.perm = PTE_AP_TO_PERM(ap);
> > + tlbe->parent_perm = tlbe->entry.perm = PTE_AP_TO_PERM(ap);
> nit: I would prefer on separate lines.
Will do.
> > tlbe->level = level;
> > tlbe->granule = granule_sz;
> > return 0;
> > @@ -515,7 +515,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> > tlbe->entry.translated_addr = gpa;
> > tlbe->entry.iova = ipa & ~mask;
> > tlbe->entry.addr_mask = mask;
> > - tlbe->entry.perm = s2ap;
> > + tlbe->parent_perm = tlbe->entry.perm = s2ap;
> > tlbe->level = level;
> > tlbe->granule = granule_sz;
> > return 0;
> > @@ -530,6 +530,27 @@ error:
> > return -EINVAL;
> > }
> >
> > +/* combine 2 TLB entries and return in tlbe in nested config. */
> suggestion: combine S1 and S2 TLB entries into a single entry. As a
> result the S1 entry is overriden with combined data.
Will do.
> > +static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
> > + SMMUTLBEntry *tlbe_s2,
> > + dma_addr_t iova,
> > + SMMUTransCfg *cfg)
> > +{
> > + if (tlbe_s2->entry.addr_mask < tlbe->entry.addr_mask) {
> > + tlbe->entry.addr_mask = tlbe_s2->entry.addr_mask;
> > + tlbe->granule = tlbe_s2->granule;
> > + tlbe->level = tlbe_s2->level;
> > + }
> > +
> > + tlbe->entry.translated_addr = CACHED_ENTRY_TO_ADDR(tlbe_s2,
> > + tlbe->entry.translated_addr);
> > +
> > + tlbe->entry.iova = iova & ~tlbe->entry.addr_mask;
> > + /* parent_perm has s2 perm while perm has s1 perm. */
>
> suggestion: while perm keeps s1 perm.
>
Will do.
Thanks,
Mostafa
> > + tlbe->parent_perm = tlbe_s2->entry.perm;
> > + return;
> > +}
> > +
> > /**
> > * smmu_ptw - Walk the page tables for an IOVA, according to @cfg
> > *
> > @@ -607,9 +628,12 @@ SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
> >
> > cached_entry = smmu_iotlb_lookup(bs, cfg, &tt_combined, aligned_addr);
> > if (cached_entry) {
> > - if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) {
> > + if ((flag & IOMMU_WO) && !(cached_entry->entry.perm &
> > + cached_entry->parent_perm & IOMMU_WO)) {
> > info->type = SMMU_PTW_ERR_PERMISSION;
> > - info->stage = cfg->stage;
> > + info->stage = !(cached_entry->entry.perm & IOMMU_WO) ?
> > + SMMU_STAGE_1 :
> > + SMMU_STAGE_2;
> > return NULL;
> > }
> > return cached_entry;
> > diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> > index 09d3b9e734..1db566d451 100644
> > --- a/include/hw/arm/smmu-common.h
> > +++ b/include/hw/arm/smmu-common.h
> > @@ -77,6 +77,7 @@ typedef struct SMMUTLBEntry {
> > IOMMUTLBEntry entry;
> > uint8_t level;
> > uint8_t granule;
> > + IOMMUAccessFlags parent_perm;
> > } SMMUTLBEntry;
> >
> > /* Stage-2 configuration. */
> Thanks
>
> Eric
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 08/18] hw/arm/smmu-common: Add support for nested TLB
2024-05-16 15:20 ` Mostafa Saleh
@ 2024-05-20 8:20 ` Eric Auger
2024-05-22 12:44 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-20 8:20 UTC (permalink / raw)
To: Mostafa Saleh
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 5/16/24 17:20, Mostafa Saleh wrote:
> Hi Eric,
>
> On Wed, May 15, 2024 at 03:48:05PM +0200, Eric Auger wrote:
>> Hi Mostafa,
>>
>> On 4/29/24 05:23, Mostafa Saleh wrote:
>>> This patch adds support for nested(combined) TLB entries.
>> space between nested and (.
> Will do.
>>> The main function combine_tlb() is not used here but in the next
>>> patches, but to simplify the patches it is introduced first.
>>>
>>> Main changes:
>>> 1) New entry added in the TLB, parent_perm, for nested TLB, holds the
>> s/entry/field, s/TLB/SMMUTLBEntry struct
> Will do.
>>> stage-2 permission, this can be used to know the origin of a
>>> permission fault from a cached entry as caching the “and” of the
>>> permissions loses this information.
>>>
>>> SMMUPTWEventInfo is used to hold information about PTW faults so
>>> the event can be populated, the value of stage (which maps to S2
>>> in the event) used to be set based on the current stage for TLB
>> I don't understand "(which maps to S2 in the event)". What do you mean?
>> This could be S1 or S2 depending on the active stage, no?
> Not really, if the IPA size is larger than S2 input size, this is
> considered stage-1 fault.
>
> For TLB permission fault, yes, that is how it is decided.
> However, with nesting, a permission fault from a cached entry can be
> from a stage-1 or stage-2, that’s why we now cache both and not just
> the combined permission, and the logic to set fault stage is modified
> accordingly.
I meant in smmu_translate() we initially had for permission fault
info->stage = cfg->stage whcih can be S1 or S2. Hence the fact I do not
understand the sentence
the value of stage (which maps to S2 in the event)
I understand that with nested this computation needs to change because the permission can be linked to either the S1 or S2 stage.
Maybe that's just a matter or rephrasing?
>>> permission faults, however with the parent_perm, it is now set
>>> based on which perm has the missing permission
>>>
>>> When nesting is not enabled it has the same value as perm which
>>> doesn't change the logic.
>>>
>>> 2) As combined TLB implementation is used, the combination logic
>>> chooses:
>>> - tg and level from the entry which has the smallest addr_mask.
>> tbh I am scared bout swapping s1/s2 tg and level. In smmu_iotlb_lookup()
>> I see tt->granule_sz being used which is s1 data. I mean it is not
>> obvious to me this is correct. Could you maybe give more explanations
>> detailing why/how this is guaranted to work.
> As you mentioned the next patch reworks the lookup logic, I can reorder
> the 2 patches if that is better, please let me know what you think?
Yes if you manage to reorder that may be more logical because otherwise
it looks incorrect.
>
>> Can you give additional details about what s1+s2 combinations were tested?
> I tested with S1 and S2 4K pages
> S1 level = 3 and S2 level = 3
> S1 level = 2 and S2 level = 3
> S1 level = 3 and S2 level = 2
> S1 level = 1 and S2 level = 2
>
> And also tested with with S1 64K granule and S2 4K.
OK, I would suggest you mention that in the coverletter because it is
reassuring and the combination is not totally obvious - at least to me ;-) -
Eric
>
>>> - Based on that the iova that would be cached is recalculated.
>>> - Translated_addr is chosen from stage-2.
>>>
>>> Signed-off-by: Mostafa Saleh <smostafa@google.com>
>>> ---
>>> hw/arm/smmu-common.c | 32 ++++++++++++++++++++++++++++----
>>> include/hw/arm/smmu-common.h | 1 +
>>> 2 files changed, 29 insertions(+), 4 deletions(-)
>>>
>>> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
>>> index 21982621c0..0d6945fa54 100644
>>> --- a/hw/arm/smmu-common.c
>>> +++ b/hw/arm/smmu-common.c
>>> @@ -394,7 +394,7 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
>>> tlbe->entry.translated_addr = gpa;
>>> tlbe->entry.iova = iova & ~mask;
>>> tlbe->entry.addr_mask = mask;
>>> - tlbe->entry.perm = PTE_AP_TO_PERM(ap);
>>> + tlbe->parent_perm = tlbe->entry.perm = PTE_AP_TO_PERM(ap);
>> nit: I would prefer on separate lines.
> Will do.
>
>>> tlbe->level = level;
>>> tlbe->granule = granule_sz;
>>> return 0;
>>> @@ -515,7 +515,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
>>> tlbe->entry.translated_addr = gpa;
>>> tlbe->entry.iova = ipa & ~mask;
>>> tlbe->entry.addr_mask = mask;
>>> - tlbe->entry.perm = s2ap;
>>> + tlbe->parent_perm = tlbe->entry.perm = s2ap;
>>> tlbe->level = level;
>>> tlbe->granule = granule_sz;
>>> return 0;
>>> @@ -530,6 +530,27 @@ error:
>>> return -EINVAL;
>>> }
>>>
>>> +/* combine 2 TLB entries and return in tlbe in nested config. */
>> suggestion: combine S1 and S2 TLB entries into a single entry. As a
>> result the S1 entry is overriden with combined data.
> Will do.
>
>>> +static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
>>> + SMMUTLBEntry *tlbe_s2,
>>> + dma_addr_t iova,
>>> + SMMUTransCfg *cfg)
>>> +{
>>> + if (tlbe_s2->entry.addr_mask < tlbe->entry.addr_mask) {
>>> + tlbe->entry.addr_mask = tlbe_s2->entry.addr_mask;
>>> + tlbe->granule = tlbe_s2->granule;
>>> + tlbe->level = tlbe_s2->level;
>>> + }
>>> +
>>> + tlbe->entry.translated_addr = CACHED_ENTRY_TO_ADDR(tlbe_s2,
>>> + tlbe->entry.translated_addr);
>>> +
>>> + tlbe->entry.iova = iova & ~tlbe->entry.addr_mask;
>>> + /* parent_perm has s2 perm while perm has s1 perm. */
>> suggestion: while perm keeps s1 perm.
>>
> Will do.
>
> Thanks,
> Mostafa
>>> + tlbe->parent_perm = tlbe_s2->entry.perm;
>>> + return;
>>> +}
>>> +
>>> /**
>>> * smmu_ptw - Walk the page tables for an IOVA, according to @cfg
>>> *
>>> @@ -607,9 +628,12 @@ SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
>>>
>>> cached_entry = smmu_iotlb_lookup(bs, cfg, &tt_combined, aligned_addr);
>>> if (cached_entry) {
>>> - if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) {
>>> + if ((flag & IOMMU_WO) && !(cached_entry->entry.perm &
>>> + cached_entry->parent_perm & IOMMU_WO)) {
>>> info->type = SMMU_PTW_ERR_PERMISSION;
>>> - info->stage = cfg->stage;
>>> + info->stage = !(cached_entry->entry.perm & IOMMU_WO) ?
>>> + SMMU_STAGE_1 :
>>> + SMMU_STAGE_2;
>>> return NULL;
>>> }
>>> return cached_entry;
>>> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
>>> index 09d3b9e734..1db566d451 100644
>>> --- a/include/hw/arm/smmu-common.h
>>> +++ b/include/hw/arm/smmu-common.h
>>> @@ -77,6 +77,7 @@ typedef struct SMMUTLBEntry {
>>> IOMMUTLBEntry entry;
>>> uint8_t level;
>>> uint8_t granule;
>>> + IOMMUAccessFlags parent_perm;
>>> } SMMUTLBEntry;
>>>
>>> /* Stage-2 configuration. */
>> Thanks
>>
>> Eric
>>
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 08/18] hw/arm/smmu-common: Add support for nested TLB
2024-05-20 8:20 ` Eric Auger
@ 2024-05-22 12:44 ` Mostafa Saleh
2024-06-17 14:56 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-05-22 12:44 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Mon, May 20, 2024 at 10:20:43AM +0200, Eric Auger wrote:
> Hi Mostafa,
> On 5/16/24 17:20, Mostafa Saleh wrote:
> > Hi Eric,
> >
> > On Wed, May 15, 2024 at 03:48:05PM +0200, Eric Auger wrote:
> >> Hi Mostafa,
> >>
> >> On 4/29/24 05:23, Mostafa Saleh wrote:
> >>> This patch adds support for nested(combined) TLB entries.
> >> space between nested and (.
> > Will do.
> >>> The main function combine_tlb() is not used here but in the next
> >>> patches, but to simplify the patches it is introduced first.
> >>>
> >>> Main changes:
> >>> 1) New entry added in the TLB, parent_perm, for nested TLB, holds the
> >> s/entry/field, s/TLB/SMMUTLBEntry struct
> > Will do.
> >>> stage-2 permission, this can be used to know the origin of a
> >>> permission fault from a cached entry as caching the “and” of the
> >>> permissions loses this information.
> >>>
> >>> SMMUPTWEventInfo is used to hold information about PTW faults so
> >>> the event can be populated, the value of stage (which maps to S2
> >>> in the event) used to be set based on the current stage for TLB
> >> I don't understand "(which maps to S2 in the event)". What do you mean?
> >> This could be S1 or S2 depending on the active stage, no?
> > Not really, if the IPA size is larger than S2 input size, this is
> > considered stage-1 fault.
> >
> > For TLB permission fault, yes, that is how it is decided.
> > However, with nesting, a permission fault from a cached entry can be
> > from a stage-1 or stage-2, that’s why we now cache both and not just
> > the combined permission, and the logic to set fault stage is modified
> > accordingly.
> I meant in smmu_translate() we initially had for permission fault
> info->stage = cfg->stage whcih can be S1 or S2. Hence the fact I do not
> understand the sentence
>
> the value of stage (which maps to S2 in the event)
>
> I understand that with nested this computation needs to change because the permission can be linked to either the S1 or S2 stage.
> Maybe that's just a matter or rephrasing?
>
I see, that’s already how it is used now, I will rephrase it in case
it is confusing.
>
> >>> permission faults, however with the parent_perm, it is now set
> >>> based on which perm has the missing permission
> >>>
> >>> When nesting is not enabled it has the same value as perm which
> >>> doesn't change the logic.
> >>>
> >>> 2) As combined TLB implementation is used, the combination logic
> >>> chooses:
> >>> - tg and level from the entry which has the smallest addr_mask.
> >> tbh I am scared bout swapping s1/s2 tg and level. In smmu_iotlb_lookup()
> >> I see tt->granule_sz being used which is s1 data. I mean it is not
> >> obvious to me this is correct. Could you maybe give more explanations
> >> detailing why/how this is guaranted to work.
> > As you mentioned the next patch reworks the lookup logic, I can reorder
> > the 2 patches if that is better, please let me know what you think?
> Yes if you manage to reorder that may be more logical because otherwise
> it looks incorrect.
Will do.
> >
> >> Can you give additional details about what s1+s2 combinations were tested?
> > I tested with S1 and S2 4K pages
> > S1 level = 3 and S2 level = 3
> > S1 level = 2 and S2 level = 3
> > S1 level = 3 and S2 level = 2
> > S1 level = 1 and S2 level = 2
> >
> > And also tested with with S1 64K granule and S2 4K.
> OK, I would suggest you mention that in the coverletter because it is
> reassuring and the combination is not totally obvious - at least to me ;-) -
Will do.
Thanks,
Mostafa
>
> Eric
> >
> >>> - Based on that the iova that would be cached is recalculated.
> >>> - Translated_addr is chosen from stage-2.
> >>>
> >>> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> >>> ---
> >>> hw/arm/smmu-common.c | 32 ++++++++++++++++++++++++++++----
> >>> include/hw/arm/smmu-common.h | 1 +
> >>> 2 files changed, 29 insertions(+), 4 deletions(-)
> >>>
> >>> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> >>> index 21982621c0..0d6945fa54 100644
> >>> --- a/hw/arm/smmu-common.c
> >>> +++ b/hw/arm/smmu-common.c
> >>> @@ -394,7 +394,7 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
> >>> tlbe->entry.translated_addr = gpa;
> >>> tlbe->entry.iova = iova & ~mask;
> >>> tlbe->entry.addr_mask = mask;
> >>> - tlbe->entry.perm = PTE_AP_TO_PERM(ap);
> >>> + tlbe->parent_perm = tlbe->entry.perm = PTE_AP_TO_PERM(ap);
> >> nit: I would prefer on separate lines.
> > Will do.
> >
> >>> tlbe->level = level;
> >>> tlbe->granule = granule_sz;
> >>> return 0;
> >>> @@ -515,7 +515,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> >>> tlbe->entry.translated_addr = gpa;
> >>> tlbe->entry.iova = ipa & ~mask;
> >>> tlbe->entry.addr_mask = mask;
> >>> - tlbe->entry.perm = s2ap;
> >>> + tlbe->parent_perm = tlbe->entry.perm = s2ap;
> >>> tlbe->level = level;
> >>> tlbe->granule = granule_sz;
> >>> return 0;
> >>> @@ -530,6 +530,27 @@ error:
> >>> return -EINVAL;
> >>> }
> >>>
> >>> +/* combine 2 TLB entries and return in tlbe in nested config. */
> >> suggestion: combine S1 and S2 TLB entries into a single entry. As a
> >> result the S1 entry is overriden with combined data.
> > Will do.
> >
> >>> +static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
> >>> + SMMUTLBEntry *tlbe_s2,
> >>> + dma_addr_t iova,
> >>> + SMMUTransCfg *cfg)
> >>> +{
> >>> + if (tlbe_s2->entry.addr_mask < tlbe->entry.addr_mask) {
> >>> + tlbe->entry.addr_mask = tlbe_s2->entry.addr_mask;
> >>> + tlbe->granule = tlbe_s2->granule;
> >>> + tlbe->level = tlbe_s2->level;
> >>> + }
> >>> +
> >>> + tlbe->entry.translated_addr = CACHED_ENTRY_TO_ADDR(tlbe_s2,
> >>> + tlbe->entry.translated_addr);
> >>> +
> >>> + tlbe->entry.iova = iova & ~tlbe->entry.addr_mask;
> >>> + /* parent_perm has s2 perm while perm has s1 perm. */
> >> suggestion: while perm keeps s1 perm.
> >>
> > Will do.
> >
> > Thanks,
> > Mostafa
> >>> + tlbe->parent_perm = tlbe_s2->entry.perm;
> >>> + return;
> >>> +}
> >>> +
> >>> /**
> >>> * smmu_ptw - Walk the page tables for an IOVA, according to @cfg
> >>> *
> >>> @@ -607,9 +628,12 @@ SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
> >>>
> >>> cached_entry = smmu_iotlb_lookup(bs, cfg, &tt_combined, aligned_addr);
> >>> if (cached_entry) {
> >>> - if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) {
> >>> + if ((flag & IOMMU_WO) && !(cached_entry->entry.perm &
> >>> + cached_entry->parent_perm & IOMMU_WO)) {
> >>> info->type = SMMU_PTW_ERR_PERMISSION;
> >>> - info->stage = cfg->stage;
> >>> + info->stage = !(cached_entry->entry.perm & IOMMU_WO) ?
> >>> + SMMU_STAGE_1 :
> >>> + SMMU_STAGE_2;
> >>> return NULL;
> >>> }
> >>> return cached_entry;
> >>> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> >>> index 09d3b9e734..1db566d451 100644
> >>> --- a/include/hw/arm/smmu-common.h
> >>> +++ b/include/hw/arm/smmu-common.h
> >>> @@ -77,6 +77,7 @@ typedef struct SMMUTLBEntry {
> >>> IOMMUTLBEntry entry;
> >>> uint8_t level;
> >>> uint8_t granule;
> >>> + IOMMUAccessFlags parent_perm;
> >>> } SMMUTLBEntry;
> >>>
> >>> /* Stage-2 configuration. */
> >> Thanks
> >>
> >> Eric
> >>
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 08/18] hw/arm/smmu-common: Add support for nested TLB
2024-05-22 12:44 ` Mostafa Saleh
@ 2024-06-17 14:56 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-06-17 14:56 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
On Wed, May 22, 2024 at 1:44 PM Mostafa Saleh <smostafa@google.com> wrote:
>
> Hi Eric,
>
> On Mon, May 20, 2024 at 10:20:43AM +0200, Eric Auger wrote:
> > Hi Mostafa,
> > On 5/16/24 17:20, Mostafa Saleh wrote:
> > > Hi Eric,
> > >
> > > On Wed, May 15, 2024 at 03:48:05PM +0200, Eric Auger wrote:
> > >> Hi Mostafa,
> > >>
> > >> On 4/29/24 05:23, Mostafa Saleh wrote:
> > >>> This patch adds support for nested(combined) TLB entries.
> > >> space between nested and (.
> > > Will do.
> > >>> The main function combine_tlb() is not used here but in the next
> > >>> patches, but to simplify the patches it is introduced first.
> > >>>
> > >>> Main changes:
> > >>> 1) New entry added in the TLB, parent_perm, for nested TLB, holds the
> > >> s/entry/field, s/TLB/SMMUTLBEntry struct
> > > Will do.
> > >>> stage-2 permission, this can be used to know the origin of a
> > >>> permission fault from a cached entry as caching the “and” of the
> > >>> permissions loses this information.
> > >>>
> > >>> SMMUPTWEventInfo is used to hold information about PTW faults so
> > >>> the event can be populated, the value of stage (which maps to S2
> > >>> in the event) used to be set based on the current stage for TLB
> > >> I don't understand "(which maps to S2 in the event)". What do you mean?
> > >> This could be S1 or S2 depending on the active stage, no?
> > > Not really, if the IPA size is larger than S2 input size, this is
> > > considered stage-1 fault.
> > >
> > > For TLB permission fault, yes, that is how it is decided.
> > > However, with nesting, a permission fault from a cached entry can be
> > > from a stage-1 or stage-2, that’s why we now cache both and not just
> > > the combined permission, and the logic to set fault stage is modified
> > > accordingly.
> > I meant in smmu_translate() we initially had for permission fault
> > info->stage = cfg->stage whcih can be S1 or S2. Hence the fact I do not
> > understand the sentence
> >
> > the value of stage (which maps to S2 in the event)
> >
> > I understand that with nested this computation needs to change because the permission can be linked to either the S1 or S2 stage.
> > Maybe that's just a matter or rephrasing?
> >
>
> I see, that’s already how it is used now, I will rephrase it in case
> it is confusing.
>
After reading the mail again I think I get the confusion here, the bit
that indicates if the event is stage-1 or stage-2 is called “S2” in
the spec :)
and that’s what the commit is referring to, but I will remove this
sentence as it doesn’t add much in this context.
> >
> > >>> permission faults, however with the parent_perm, it is now set
> > >>> based on which perm has the missing permission
> > >>>
> > >>> When nesting is not enabled it has the same value as perm which
> > >>> doesn't change the logic.
> > >>>
> > >>> 2) As combined TLB implementation is used, the combination logic
> > >>> chooses:
> > >>> - tg and level from the entry which has the smallest addr_mask.
> > >> tbh I am scared bout swapping s1/s2 tg and level. In smmu_iotlb_lookup()
> > >> I see tt->granule_sz being used which is s1 data. I mean it is not
> > >> obvious to me this is correct. Could you maybe give more explanations
> > >> detailing why/how this is guaranted to work.
> > > As you mentioned the next patch reworks the lookup logic, I can reorder
> > > the 2 patches if that is better, please let me know what you think?
> > Yes if you manage to reorder that may be more logical because otherwise
> > it looks incorrect.
>
> Will do.
> > >
> > >> Can you give additional details about what s1+s2 combinations were tested?
> > > I tested with S1 and S2 4K pages
> > > S1 level = 3 and S2 level = 3
> > > S1 level = 2 and S2 level = 3
> > > S1 level = 3 and S2 level = 2
> > > S1 level = 1 and S2 level = 2
> > >
> > > And also tested with with S1 64K granule and S2 4K.
> > OK, I would suggest you mention that in the coverletter because it is
> > reassuring and the combination is not totally obvious - at least to me ;-) -
>
> Will do.
>
> Thanks,
> Mostafa
> >
> > Eric
> > >
> > >>> - Based on that the iova that would be cached is recalculated.
> > >>> - Translated_addr is chosen from stage-2.
> > >>>
> > >>> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > >>> ---
> > >>> hw/arm/smmu-common.c | 32 ++++++++++++++++++++++++++++----
> > >>> include/hw/arm/smmu-common.h | 1 +
> > >>> 2 files changed, 29 insertions(+), 4 deletions(-)
> > >>>
> > >>> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> > >>> index 21982621c0..0d6945fa54 100644
> > >>> --- a/hw/arm/smmu-common.c
> > >>> +++ b/hw/arm/smmu-common.c
> > >>> @@ -394,7 +394,7 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
> > >>> tlbe->entry.translated_addr = gpa;
> > >>> tlbe->entry.iova = iova & ~mask;
> > >>> tlbe->entry.addr_mask = mask;
> > >>> - tlbe->entry.perm = PTE_AP_TO_PERM(ap);
> > >>> + tlbe->parent_perm = tlbe->entry.perm = PTE_AP_TO_PERM(ap);
> > >> nit: I would prefer on separate lines.
> > > Will do.
> > >
> > >>> tlbe->level = level;
> > >>> tlbe->granule = granule_sz;
> > >>> return 0;
> > >>> @@ -515,7 +515,7 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> > >>> tlbe->entry.translated_addr = gpa;
> > >>> tlbe->entry.iova = ipa & ~mask;
> > >>> tlbe->entry.addr_mask = mask;
> > >>> - tlbe->entry.perm = s2ap;
> > >>> + tlbe->parent_perm = tlbe->entry.perm = s2ap;
> > >>> tlbe->level = level;
> > >>> tlbe->granule = granule_sz;
> > >>> return 0;
> > >>> @@ -530,6 +530,27 @@ error:
> > >>> return -EINVAL;
> > >>> }
> > >>>
> > >>> +/* combine 2 TLB entries and return in tlbe in nested config. */
> > >> suggestion: combine S1 and S2 TLB entries into a single entry. As a
> > >> result the S1 entry is overriden with combined data.
> > > Will do.
> > >
> > >>> +static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
> > >>> + SMMUTLBEntry *tlbe_s2,
> > >>> + dma_addr_t iova,
> > >>> + SMMUTransCfg *cfg)
> > >>> +{
> > >>> + if (tlbe_s2->entry.addr_mask < tlbe->entry.addr_mask) {
> > >>> + tlbe->entry.addr_mask = tlbe_s2->entry.addr_mask;
> > >>> + tlbe->granule = tlbe_s2->granule;
> > >>> + tlbe->level = tlbe_s2->level;
> > >>> + }
> > >>> +
> > >>> + tlbe->entry.translated_addr = CACHED_ENTRY_TO_ADDR(tlbe_s2,
> > >>> + tlbe->entry.translated_addr);
> > >>> +
> > >>> + tlbe->entry.iova = iova & ~tlbe->entry.addr_mask;
> > >>> + /* parent_perm has s2 perm while perm has s1 perm. */
> > >> suggestion: while perm keeps s1 perm.
> > >>
> > > Will do.
> > >
> > > Thanks,
> > > Mostafa
> > >>> + tlbe->parent_perm = tlbe_s2->entry.perm;
> > >>> + return;
> > >>> +}
> > >>> +
> > >>> /**
> > >>> * smmu_ptw - Walk the page tables for an IOVA, according to @cfg
> > >>> *
> > >>> @@ -607,9 +628,12 @@ SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
> > >>>
> > >>> cached_entry = smmu_iotlb_lookup(bs, cfg, &tt_combined, aligned_addr);
> > >>> if (cached_entry) {
> > >>> - if ((flag & IOMMU_WO) && !(cached_entry->entry.perm & IOMMU_WO)) {
> > >>> + if ((flag & IOMMU_WO) && !(cached_entry->entry.perm &
> > >>> + cached_entry->parent_perm & IOMMU_WO)) {
> > >>> info->type = SMMU_PTW_ERR_PERMISSION;
> > >>> - info->stage = cfg->stage;
> > >>> + info->stage = !(cached_entry->entry.perm & IOMMU_WO) ?
> > >>> + SMMU_STAGE_1 :
> > >>> + SMMU_STAGE_2;
> > >>> return NULL;
> > >>> }
> > >>> return cached_entry;
> > >>> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> > >>> index 09d3b9e734..1db566d451 100644
> > >>> --- a/include/hw/arm/smmu-common.h
> > >>> +++ b/include/hw/arm/smmu-common.h
> > >>> @@ -77,6 +77,7 @@ typedef struct SMMUTLBEntry {
> > >>> IOMMUTLBEntry entry;
> > >>> uint8_t level;
> > >>> uint8_t granule;
> > >>> + IOMMUAccessFlags parent_perm;
> > >>> } SMMUTLBEntry;
> > >>>
> > >>> /* Stage-2 configuration. */
> > >> Thanks
> > >>
> > >> Eric
> > >>
> >
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 09/18] hw/arm/smmu-common: Rework TLB lookup for nesting
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (7 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 08/18] hw/arm/smmu-common: Add support for nested TLB Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-15 13:54 ` Eric Auger
2024-05-20 8:27 ` Eric Auger
2024-04-29 3:23 ` [RFC PATCH v3 10/18] hw/arm/smmu-common: Support nested translation Mostafa Saleh
` (10 subsequent siblings)
19 siblings, 2 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
In the previous patch, comine_tlb() was added which combines 2 TLB
entries into one, which chooses the granule and level from the
smallest entry.
This means that a nested translation, an entry can be cached with the
granule of stage-2 and not stage-1.
However, the lookup for an IOVA in nested configuration is done with
stage-1 granule, this patch reworks lookup in that case, so it falls
back to stage-2 granule if no entry is found using stage-1 granule.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmu-common.c | 24 ++++++++++++++++++++++--
1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 0d6945fa54..c67af3bc6d 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -66,8 +66,10 @@ SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
return key;
}
-SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
- SMMUTransTableInfo *tt, hwaddr iova)
+static SMMUTLBEntry *smmu_iotlb_lookup_all_levels(SMMUState *bs,
+ SMMUTransCfg *cfg,
+ SMMUTransTableInfo *tt,
+ hwaddr iova)
{
uint8_t tg = (tt->granule_sz - 10) / 2;
uint8_t inputsize = 64 - tt->tsz;
@@ -88,6 +90,24 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
}
level++;
}
+ return entry;
+}
+
+SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
+ SMMUTransTableInfo *tt, hwaddr iova)
+{
+ SMMUTLBEntry *entry = NULL;
+
+ entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
+ /*
+ * For nested translation also try the s2 granule, as the TLB will insert
+ * it if the size of s2 tlb entry was smaller.
+ */
+ if (!entry && (cfg->stage == SMMU_NESTED) &&
+ (cfg->s2cfg.granule_sz != tt->granule_sz)) {
+ tt->granule_sz = cfg->s2cfg.granule_sz;
+ entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
+ }
if (entry) {
cfg->iotlb_hits++;
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 09/18] hw/arm/smmu-common: Rework TLB lookup for nesting
2024-04-29 3:23 ` [RFC PATCH v3 09/18] hw/arm/smmu-common: Rework TLB lookup for nesting Mostafa Saleh
@ 2024-05-15 13:54 ` Eric Auger
2024-05-16 15:30 ` Mostafa Saleh
2024-05-20 8:27 ` Eric Auger
1 sibling, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-15 13:54 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
On 4/29/24 05:23, Mostafa Saleh wrote:
> In the previous patch, comine_tlb() was added which combines 2 TLB
combine
> entries into one, which chooses the granule and level from the
> smallest entry.
>
> This means that a nested translation, an entry can be cached with the
that with nested translation
> granule of stage-2 and not stage-1.
>
> However, the lookup for an IOVA in nested configuration is done with
> stage-1 granule, this patch reworks lookup in that case, so it falls
> back to stage-2 granule if no entry is found using stage-1 granule.
I should have read that before commenting previous patch ;-)
Anyway this shows that something is missing in previous patch, at least
the above explanation ;-)
Eric
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmu-common.c | 24 ++++++++++++++++++++++--
> 1 file changed, 22 insertions(+), 2 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index 0d6945fa54..c67af3bc6d 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -66,8 +66,10 @@ SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> return key;
> }
>
> -SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> - SMMUTransTableInfo *tt, hwaddr iova)
> +static SMMUTLBEntry *smmu_iotlb_lookup_all_levels(SMMUState *bs,
> + SMMUTransCfg *cfg,
> + SMMUTransTableInfo *tt,
> + hwaddr iova)
> {
> uint8_t tg = (tt->granule_sz - 10) / 2;
> uint8_t inputsize = 64 - tt->tsz;
> @@ -88,6 +90,24 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> }
> level++;
> }
> + return entry;
> +}
> +
> +SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> + SMMUTransTableInfo *tt, hwaddr iova)
> +{
> + SMMUTLBEntry *entry = NULL;
> +
> + entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
> + /*
> + * For nested translation also try the s2 granule, as the TLB will insert
> + * it if the size of s2 tlb entry was smaller.
> + */
> + if (!entry && (cfg->stage == SMMU_NESTED) &&
> + (cfg->s2cfg.granule_sz != tt->granule_sz)) {
> + tt->granule_sz = cfg->s2cfg.granule_sz;
> + entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
> + }
>
> if (entry) {
> cfg->iotlb_hits++;
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 09/18] hw/arm/smmu-common: Rework TLB lookup for nesting
2024-05-15 13:54 ` Eric Auger
@ 2024-05-16 15:30 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-05-16 15:30 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Wed, May 15, 2024 at 03:54:36PM +0200, Eric Auger wrote:
>
>
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > In the previous patch, comine_tlb() was added which combines 2 TLB
> combine
Will do.
> > entries into one, which chooses the granule and level from the
> > smallest entry.
> >
> > This means that a nested translation, an entry can be cached with the
> that with nested translation
Will do.
> > granule of stage-2 and not stage-1.
> >
> > However, the lookup for an IOVA in nested configuration is done with
> > stage-1 granule, this patch reworks lookup in that case, so it falls
> > back to stage-2 granule if no entry is found using stage-1 granule.
> I should have read that before commenting previous patch ;-)
> Anyway this shows that something is missing in previous patch, at least
> the above explanation ;-)
Yup, I can add a comment in the previous patch or reorder them, let me
know what you prefer.
Thanks,
Mostafa
>
> Eric
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmu-common.c | 24 ++++++++++++++++++++++--
> > 1 file changed, 22 insertions(+), 2 deletions(-)
> >
> > diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> > index 0d6945fa54..c67af3bc6d 100644
> > --- a/hw/arm/smmu-common.c
> > +++ b/hw/arm/smmu-common.c
> > @@ -66,8 +66,10 @@ SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> > return key;
> > }
> >
> > -SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> > - SMMUTransTableInfo *tt, hwaddr iova)
> > +static SMMUTLBEntry *smmu_iotlb_lookup_all_levels(SMMUState *bs,
> > + SMMUTransCfg *cfg,
> > + SMMUTransTableInfo *tt,
> > + hwaddr iova)
> > {
> > uint8_t tg = (tt->granule_sz - 10) / 2;
> > uint8_t inputsize = 64 - tt->tsz;
> > @@ -88,6 +90,24 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> > }
> > level++;
> > }
> > + return entry;
> > +}
> > +
> > +SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> > + SMMUTransTableInfo *tt, hwaddr iova)
> > +{
> > + SMMUTLBEntry *entry = NULL;
> > +
> > + entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
> > + /*
> > + * For nested translation also try the s2 granule, as the TLB will insert
> > + * it if the size of s2 tlb entry was smaller.
> > + */
> > + if (!entry && (cfg->stage == SMMU_NESTED) &&
> > + (cfg->s2cfg.granule_sz != tt->granule_sz)) {
> > + tt->granule_sz = cfg->s2cfg.granule_sz;
> > + entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
> > + }
> >
> > if (entry) {
> > cfg->iotlb_hits++;
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 09/18] hw/arm/smmu-common: Rework TLB lookup for nesting
2024-04-29 3:23 ` [RFC PATCH v3 09/18] hw/arm/smmu-common: Rework TLB lookup for nesting Mostafa Saleh
2024-05-15 13:54 ` Eric Auger
@ 2024-05-20 8:27 ` Eric Auger
2024-05-22 12:47 ` Mostafa Saleh
1 sibling, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-20 8:27 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> In the previous patch, comine_tlb() was added which combines 2 TLB
> entries into one, which chooses the granule and level from the
> smallest entry.
>
> This means that a nested translation, an entry can be cached with the
> granule of stage-2 and not stage-1.
>
> However, the lookup for an IOVA in nested configuration is done with
> stage-1 granule, this patch reworks lookup in that case, so it falls
> back to stage-2 granule if no entry is found using stage-1 granule.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmu-common.c | 24 ++++++++++++++++++++++--
> 1 file changed, 22 insertions(+), 2 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index 0d6945fa54..c67af3bc6d 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -66,8 +66,10 @@ SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> return key;
> }
>
> -SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> - SMMUTransTableInfo *tt, hwaddr iova)
> +static SMMUTLBEntry *smmu_iotlb_lookup_all_levels(SMMUState *bs,
> + SMMUTransCfg *cfg,
> + SMMUTransTableInfo *tt,
> + hwaddr iova)
> {
> uint8_t tg = (tt->granule_sz - 10) / 2;
> uint8_t inputsize = 64 - tt->tsz;
> @@ -88,6 +90,24 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> }
> level++;
> }
> + return entry;
> +}
> +
> +SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> + SMMUTransTableInfo *tt, hwaddr iova)
> +{
> + SMMUTLBEntry *entry = NULL;
> +
> + entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
> + /*
> + * For nested translation also try the s2 granule, as the TLB will insert
> + * it if the size of s2 tlb entry was smaller.
> + */
> + if (!entry && (cfg->stage == SMMU_NESTED) &&
> + (cfg->s2cfg.granule_sz != tt->granule_sz)) {
> + tt->granule_sz = cfg->s2cfg.granule_sz;
is it safe to alter the tt->granule_sz without restoring it? In the
positive I think this would deserve a comment.
Eric
> + entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
> + }
>
> if (entry) {
> cfg->iotlb_hits++;
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 09/18] hw/arm/smmu-common: Rework TLB lookup for nesting
2024-05-20 8:27 ` Eric Auger
@ 2024-05-22 12:47 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-05-22 12:47 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Mon, May 20, 2024 at 10:27:50AM +0200, Eric Auger wrote:
> Hi Mostafa,
>
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > In the previous patch, comine_tlb() was added which combines 2 TLB
> > entries into one, which chooses the granule and level from the
> > smallest entry.
> >
> > This means that a nested translation, an entry can be cached with the
> > granule of stage-2 and not stage-1.
> >
> > However, the lookup for an IOVA in nested configuration is done with
> > stage-1 granule, this patch reworks lookup in that case, so it falls
> > back to stage-2 granule if no entry is found using stage-1 granule.
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmu-common.c | 24 ++++++++++++++++++++++--
> > 1 file changed, 22 insertions(+), 2 deletions(-)
> >
> > diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> > index 0d6945fa54..c67af3bc6d 100644
> > --- a/hw/arm/smmu-common.c
> > +++ b/hw/arm/smmu-common.c
> > @@ -66,8 +66,10 @@ SMMUIOTLBKey smmu_get_iotlb_key(int asid, int vmid, uint64_t iova,
> > return key;
> > }
> >
> > -SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> > - SMMUTransTableInfo *tt, hwaddr iova)
> > +static SMMUTLBEntry *smmu_iotlb_lookup_all_levels(SMMUState *bs,
> > + SMMUTransCfg *cfg,
> > + SMMUTransTableInfo *tt,
> > + hwaddr iova)
> > {
> > uint8_t tg = (tt->granule_sz - 10) / 2;
> > uint8_t inputsize = 64 - tt->tsz;
> > @@ -88,6 +90,24 @@ SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> > }
> > level++;
> > }
> > + return entry;
> > +}
> > +
> > +SMMUTLBEntry *smmu_iotlb_lookup(SMMUState *bs, SMMUTransCfg *cfg,
> > + SMMUTransTableInfo *tt, hwaddr iova)
> > +{
> > + SMMUTLBEntry *entry = NULL;
> > +
> > + entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
> > + /*
> > + * For nested translation also try the s2 granule, as the TLB will insert
> > + * it if the size of s2 tlb entry was smaller.
> > + */
> > + if (!entry && (cfg->stage == SMMU_NESTED) &&
> > + (cfg->s2cfg.granule_sz != tt->granule_sz)) {
> > + tt->granule_sz = cfg->s2cfg.granule_sz;
> is it safe to alter the tt->granule_sz without restoring it? In the
> positive I think this would deserve a comment.
It should be safe in the current usage, I will add a comment to
clarify how the function behaves (something as the the granule_sz
would be updated to the entry tg if found)
Thanks,
Mostafa
>
> Eric
> > + entry = smmu_iotlb_lookup_all_levels(bs, cfg, tt, iova);
> > + }
> >
> > if (entry) {
> > cfg->iotlb_hits++;
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 10/18] hw/arm/smmu-common: Support nested translation
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (8 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 09/18] hw/arm/smmu-common: Rework TLB lookup for nesting Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-20 9:48 ` Eric Auger
2024-04-29 3:23 ` [RFC PATCH v3 11/18] hw/arm/smmu: Support nesting in smmuv3_range_inval() Mostafa Saleh
` (9 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
When nested translation is requested, do the following:
- Translate stage-1 IPA using stage-2 to a physical address.
- Translate stage-1 table walks using stage-2.
- Combine both to create a single TLB entry using the logic
introduced before.
For stage-1 table translation, the spec (ARM IHI 0070 F.b) says in:
7.3.12 F_WALK_EABT:
Translation of an IPA for Stage 1 descriptor fetch:
S2 == 1 (stage 2), CLASS == T
So, F_WALK_EABT is used which propagtes to CLASS == TT.
smmu_ptw() has a new argument SMMUState which include the TLB as
stage-1 table address can be cached in there.
Also in smmu_ptw() a separate path used for nesting to simplify the
code, although some logic can be combined.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmu-common.c | 67 ++++++++++++++++++++++++++++++------
include/hw/arm/smmu-common.h | 2 +-
2 files changed, 58 insertions(+), 11 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index c67af3bc6d..d48ec08947 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -306,6 +306,32 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova)
return NULL;
}
+/* Translate stage-1 table address using stage-2 page table. */
+static inline int translate_table_s1(dma_addr_t *table_addr, SMMUTransCfg *cfg,
+ SMMUPTWEventInfo *info, SMMUState *bs)
+{
+ dma_addr_t addr = *table_addr;
+ SMMUTLBEntry *cached_entry;
+ int asid;
+
+ asid = cfg->asid;
+ cfg->stage = SMMU_STAGE_2;
+ cfg->asid = -1;
+ cached_entry = smmu_translate(bs, cfg, addr, IOMMU_RO, info);
+ cfg->asid = asid;
+ cfg->stage = SMMU_NESTED;
+
+ if (cached_entry) {
+ *table_addr = CACHED_ENTRY_TO_ADDR(cached_entry, addr);
+ return 0;
+ }
+
+ info->stage = SMMU_STAGE_2;
+ info->type = SMMU_PTW_ERR_WALK_EABT;
+ info->addr = addr;
+ return -EINVAL;
+}
+
/**
* smmu_ptw_64_s1 - VMSAv8-64 Walk of the page tables for a given IOVA
* @cfg: translation config
@@ -321,7 +347,8 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova)
*/
static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
dma_addr_t iova, IOMMUAccessFlags perm,
- SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
+ SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info,
+ SMMUState *bs)
{
dma_addr_t baseaddr, indexmask;
SMMUStage stage = cfg->stage;
@@ -369,6 +396,11 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
goto error;
}
baseaddr = get_table_pte_address(pte, granule_sz);
+ if (cfg->stage == SMMU_NESTED) {
+ if (translate_table_s1(&baseaddr, cfg, info, bs)) {
+ goto error;
+ }
+ }
level++;
continue;
} else if (is_page_pte(pte, level)) {
@@ -551,10 +583,8 @@ error:
}
/* combine 2 TLB entries and return in tlbe in nested config. */
-static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
- SMMUTLBEntry *tlbe_s2,
- dma_addr_t iova,
- SMMUTransCfg *cfg)
+static void combine_tlb(SMMUTLBEntry *tlbe, SMMUTLBEntry *tlbe_s2,
+ dma_addr_t iova, SMMUTransCfg *cfg)
{
if (tlbe_s2->entry.addr_mask < tlbe->entry.addr_mask) {
tlbe->entry.addr_mask = tlbe_s2->entry.addr_mask;
@@ -579,14 +609,19 @@ static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
* @perm: tentative access type
* @tlbe: returned entry
* @info: ptw event handle
+ * @bs: smmu state which includes TLB instance
*
* return 0 on success
*/
int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
- SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
+ SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info, SMMUState *bs)
{
+ int ret;
+ SMMUTLBEntry tlbe_s2;
+ dma_addr_t ipa;
+
if (cfg->stage == SMMU_STAGE_1) {
- return smmu_ptw_64_s1(cfg, iova, perm, tlbe, info);
+ return smmu_ptw_64_s1(cfg, iova, perm, tlbe, info, bs);
} else if (cfg->stage == SMMU_STAGE_2) {
/*
* If bypassing stage 1(or unimplemented), the input address is passed
@@ -600,11 +635,23 @@ int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
tlbe->entry.perm = IOMMU_NONE;
return -EINVAL;
}
-
return smmu_ptw_64_s2(cfg, iova, perm, tlbe, info);
}
- g_assert_not_reached();
+ /* SMMU_NESTED. */
+ ret = smmu_ptw_64_s1(cfg, iova, perm, tlbe, info, bs);
+ if (ret) {
+ return ret;
+ }
+
+ ipa = CACHED_ENTRY_TO_ADDR(tlbe, iova);
+ ret = smmu_ptw_64_s2(cfg, ipa, perm, &tlbe_s2, info);
+ if (ret) {
+ return ret;
+ }
+
+ combine_tlb(tlbe, &tlbe_s2, iova, cfg);
+ return 0;
}
SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
@@ -660,7 +707,7 @@ SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
}
cached_entry = g_new0(SMMUTLBEntry, 1);
- status = smmu_ptw(cfg, aligned_addr, flag, cached_entry, info);
+ status = smmu_ptw(cfg, aligned_addr, flag, cached_entry, info, bs);
if (status) {
g_free(cached_entry);
return NULL;
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index 1db566d451..cf0fd3ec74 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -185,7 +185,7 @@ static inline uint16_t smmu_get_sid(SMMUDevice *sdev)
* pair, according to @cfg translation config
*/
int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
- SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info);
+ SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info, SMMUState *bs);
/*
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 10/18] hw/arm/smmu-common: Support nested translation
2024-04-29 3:23 ` [RFC PATCH v3 10/18] hw/arm/smmu-common: Support nested translation Mostafa Saleh
@ 2024-05-20 9:48 ` Eric Auger
2024-06-17 14:57 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-20 9:48 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> When nested translation is requested, do the following:
>
> - Translate stage-1 IPA using stage-2 to a physical address.
stage-1 table address IPA into PA through S2 stage
> - Translate stage-1 table walks using stage-2.
output of S1 stage (IPA) through S2.
> - Combine both to create a single TLB entry using the logic
> introduced before.
this applies to second only. First one is associated with an S2 TLB
entry, right?
>
> For stage-1 table translation, the spec (ARM IHI 0070 F.b) says in:
> 7.3.12 F_WALK_EABT:
> Translation of an IPA for Stage 1 descriptor fetch:
> S2 == 1 (stage 2), CLASS == T
> So, F_WALK_EABT is used which propagtes to CLASS == TT.
>
> smmu_ptw() has a new argument SMMUState which include the TLB as
> stage-1 table address can be cached in there.
>
> Also in smmu_ptw() a separate path used for nesting to simplify the
> code, although some logic can be combined.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmu-common.c | 67 ++++++++++++++++++++++++++++++------
> include/hw/arm/smmu-common.h | 2 +-
> 2 files changed, 58 insertions(+), 11 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index c67af3bc6d..d48ec08947 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -306,6 +306,32 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova)
> return NULL;
> }
>
> +/* Translate stage-1 table address using stage-2 page table. */
> +static inline int translate_table_s1(dma_addr_t *table_addr, SMMUTransCfg *cfg,
> + SMMUPTWEventInfo *info, SMMUState *bs)
would suggest translate_table_addr_ipa().
> +{
> + dma_addr_t addr = *table_addr;
> + SMMUTLBEntry *cached_entry;
> + int asid;
> +
> + asid = cfg->asid;
> + cfg->stage = SMMU_STAGE_2;
> + cfg->asid = -1;
> + cached_entry = smmu_translate(bs, cfg, addr, IOMMU_RO, info);
so this is going to be cached as an S2 entry. Maybe worth adding a comment.
> + cfg->asid = asid;
> + cfg->stage = SMMU_NESTED;
> +
> + if (cached_entry) {
> + *table_addr = CACHED_ENTRY_TO_ADDR(cached_entry, addr);
> + return 0;
> + }
> +
> + info->stage = SMMU_STAGE_2;
> + info->type = SMMU_PTW_ERR_WALK_EABT;
> + info->addr = addr;
> + return -EINVAL;
> +}
> +
> /**
> * smmu_ptw_64_s1 - VMSAv8-64 Walk of the page tables for a given IOVA
> * @cfg: translation config
> @@ -321,7 +347,8 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova)
> */
> static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
> dma_addr_t iova, IOMMUAccessFlags perm,
> - SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
> + SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info,
> + SMMUState *bs)
> {
> dma_addr_t baseaddr, indexmask;
> SMMUStage stage = cfg->stage;
> @@ -369,6 +396,11 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
> goto error;
> }
> baseaddr = get_table_pte_address(pte, granule_sz);
> + if (cfg->stage == SMMU_NESTED) {
> + if (translate_table_s1(&baseaddr, cfg, info, bs)) {
> + goto error;
> + }
> + }
> level++;
> continue;
> } else if (is_page_pte(pte, level)) {
> @@ -551,10 +583,8 @@ error:
> }
>
> /* combine 2 TLB entries and return in tlbe in nested config. */
> -static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
> - SMMUTLBEntry *tlbe_s2,
> - dma_addr_t iova,
> - SMMUTransCfg *cfg)
> +static void combine_tlb(SMMUTLBEntry *tlbe, SMMUTLBEntry *tlbe_s2,
> + dma_addr_t iova, SMMUTransCfg *cfg)
> {
> if (tlbe_s2->entry.addr_mask < tlbe->entry.addr_mask) {
> tlbe->entry.addr_mask = tlbe_s2->entry.addr_mask;
> @@ -579,14 +609,19 @@ static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
> * @perm: tentative access type
> * @tlbe: returned entry
> * @info: ptw event handle
> + * @bs: smmu state which includes TLB instance
> *
> * return 0 on success
> */
> int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
> - SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
> + SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info, SMMUState *bs)
> {
> + int ret;
> + SMMUTLBEntry tlbe_s2;
> + dma_addr_t ipa;
> +
> if (cfg->stage == SMMU_STAGE_1) {
> - return smmu_ptw_64_s1(cfg, iova, perm, tlbe, info);
> + return smmu_ptw_64_s1(cfg, iova, perm, tlbe, info, bs);
> } else if (cfg->stage == SMMU_STAGE_2) {
> /*
> * If bypassing stage 1(or unimplemented), the input address is passed
> @@ -600,11 +635,23 @@ int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
> tlbe->entry.perm = IOMMU_NONE;
> return -EINVAL;
> }
> -
spurious line change
> return smmu_ptw_64_s2(cfg, iova, perm, tlbe, info);
> }
>
> - g_assert_not_reached();
> + /* SMMU_NESTED. */
> + ret = smmu_ptw_64_s1(cfg, iova, perm, tlbe, info, bs);
> + if (ret) {
> + return ret;
> + }
> +
> + ipa = CACHED_ENTRY_TO_ADDR(tlbe, iova);
> + ret = smmu_ptw_64_s2(cfg, ipa, perm, &tlbe_s2, info);
> + if (ret) {
> + return ret;
> + }
> +
> + combine_tlb(tlbe, &tlbe_s2, iova, cfg);
> + return 0;
> }
>
> SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
> @@ -660,7 +707,7 @@ SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
> }
>
> cached_entry = g_new0(SMMUTLBEntry, 1);
> - status = smmu_ptw(cfg, aligned_addr, flag, cached_entry, info);
> + status = smmu_ptw(cfg, aligned_addr, flag, cached_entry, info, bs);
> if (status) {
> g_free(cached_entry);
> return NULL;
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index 1db566d451..cf0fd3ec74 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -185,7 +185,7 @@ static inline uint16_t smmu_get_sid(SMMUDevice *sdev)
> * pair, according to @cfg translation config
> */
> int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
> - SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info);
> + SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info, SMMUState *bs);
>
>
> /*
Thanks
Eric
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 10/18] hw/arm/smmu-common: Support nested translation
2024-05-20 9:48 ` Eric Auger
@ 2024-06-17 14:57 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-06-17 14:57 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Mon, May 20, 2024 at 11:48:18AM +0200, Eric Auger wrote:
> Hi Mostafa,
>
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > When nested translation is requested, do the following:
> >
> > - Translate stage-1 IPA using stage-2 to a physical address.
> stage-1 table address IPA into PA through S2 stage
>
Will do.
> > - Translate stage-1 table walks using stage-2.
> output of S1 stage (IPA) through S2.
Will do.
> > - Combine both to create a single TLB entry using the logic
> > introduced before.
> this applies to second only. First one is associated with an S2 TLB
> entry, right?
Yes, I will clarify that.
> >
> > For stage-1 table translation, the spec (ARM IHI 0070 F.b) says in:
> > 7.3.12 F_WALK_EABT:
> > Translation of an IPA for Stage 1 descriptor fetch:
> > S2 == 1 (stage 2), CLASS == T
> > So, F_WALK_EABT is used which propagtes to CLASS == TT.
> >
> > smmu_ptw() has a new argument SMMUState which include the TLB as
> > stage-1 table address can be cached in there.
> >
> > Also in smmu_ptw() a separate path used for nesting to simplify the
> > code, although some logic can be combined.
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmu-common.c | 67 ++++++++++++++++++++++++++++++------
> > include/hw/arm/smmu-common.h | 2 +-
> > 2 files changed, 58 insertions(+), 11 deletions(-)
> >
> > diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> > index c67af3bc6d..d48ec08947 100644
> > --- a/hw/arm/smmu-common.c
> > +++ b/hw/arm/smmu-common.c
> > @@ -306,6 +306,32 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova)
> > return NULL;
> > }
> >
> > +/* Translate stage-1 table address using stage-2 page table. */
> > +static inline int translate_table_s1(dma_addr_t *table_addr, SMMUTransCfg *cfg,
> > + SMMUPTWEventInfo *info, SMMUState *bs)
> would suggest translate_table_addr_ipa().
Wil do.
> > +{
> > + dma_addr_t addr = *table_addr;
> > + SMMUTLBEntry *cached_entry;
> > + int asid;
> > +
> > + asid = cfg->asid;
> > + cfg->stage = SMMU_STAGE_2;
> > + cfg->asid = -1;
> > + cached_entry = smmu_translate(bs, cfg, addr, IOMMU_RO, info);
> so this is going to be cached as an S2 entry. Maybe worth adding a comment.
This is part of the IPA space and it is translated using a stage-2 page table,
so it would be cached as an S2, I will add a comment quoting the spec.
Thanks,
Mostafa
> > + cfg->asid = asid;
> > + cfg->stage = SMMU_NESTED;
> > +
> > + if (cached_entry) {
> > + *table_addr = CACHED_ENTRY_TO_ADDR(cached_entry, addr);
> > + return 0;
> > + }
> > +
> > + info->stage = SMMU_STAGE_2;
> > + info->type = SMMU_PTW_ERR_WALK_EABT;
> > + info->addr = addr;
> > + return -EINVAL;
> > +}
> > +
> > /**
> > * smmu_ptw_64_s1 - VMSAv8-64 Walk of the page tables for a given IOVA
> > * @cfg: translation config
> > @@ -321,7 +347,8 @@ SMMUTransTableInfo *select_tt(SMMUTransCfg *cfg, dma_addr_t iova)
> > */
> > static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
> > dma_addr_t iova, IOMMUAccessFlags perm,
> > - SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
> > + SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info,
> > + SMMUState *bs)
> > {
> > dma_addr_t baseaddr, indexmask;
> > SMMUStage stage = cfg->stage;
> > @@ -369,6 +396,11 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
> > goto error;
> > }
> > baseaddr = get_table_pte_address(pte, granule_sz);
> > + if (cfg->stage == SMMU_NESTED) {
> > + if (translate_table_s1(&baseaddr, cfg, info, bs)) {
> > + goto error;
> > + }
> > + }
> > level++;
> > continue;
> > } else if (is_page_pte(pte, level)) {
> > @@ -551,10 +583,8 @@ error:
> > }
> >
> > /* combine 2 TLB entries and return in tlbe in nested config. */
> > -static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
> > - SMMUTLBEntry *tlbe_s2,
> > - dma_addr_t iova,
> > - SMMUTransCfg *cfg)
> > +static void combine_tlb(SMMUTLBEntry *tlbe, SMMUTLBEntry *tlbe_s2,
> > + dma_addr_t iova, SMMUTransCfg *cfg)
> > {
> > if (tlbe_s2->entry.addr_mask < tlbe->entry.addr_mask) {
> > tlbe->entry.addr_mask = tlbe_s2->entry.addr_mask;
> > @@ -579,14 +609,19 @@ static void __attribute__((unused)) combine_tlb(SMMUTLBEntry *tlbe,
> > * @perm: tentative access type
> > * @tlbe: returned entry
> > * @info: ptw event handle
> > + * @bs: smmu state which includes TLB instance
> > *
> > * return 0 on success
> > */
> > int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
> > - SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info)
> > + SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info, SMMUState *bs)
> > {
> > + int ret;
> > + SMMUTLBEntry tlbe_s2;
> > + dma_addr_t ipa;
> > +
> > if (cfg->stage == SMMU_STAGE_1) {
> > - return smmu_ptw_64_s1(cfg, iova, perm, tlbe, info);
> > + return smmu_ptw_64_s1(cfg, iova, perm, tlbe, info, bs);
> > } else if (cfg->stage == SMMU_STAGE_2) {
> > /*
> > * If bypassing stage 1(or unimplemented), the input address is passed
> > @@ -600,11 +635,23 @@ int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
> > tlbe->entry.perm = IOMMU_NONE;
> > return -EINVAL;
> > }
> > -
> spurious line change
> > return smmu_ptw_64_s2(cfg, iova, perm, tlbe, info);
> > }
> >
> > - g_assert_not_reached();
> > + /* SMMU_NESTED. */
> > + ret = smmu_ptw_64_s1(cfg, iova, perm, tlbe, info, bs);
> > + if (ret) {
> > + return ret;
> > + }
> > +
> > + ipa = CACHED_ENTRY_TO_ADDR(tlbe, iova);
> > + ret = smmu_ptw_64_s2(cfg, ipa, perm, &tlbe_s2, info);
> > + if (ret) {
> > + return ret;
> > + }
> > +
> > + combine_tlb(tlbe, &tlbe_s2, iova, cfg);
> > + return 0;
> > }
> >
> > SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
> > @@ -660,7 +707,7 @@ SMMUTLBEntry *smmu_translate(SMMUState *bs, SMMUTransCfg *cfg, dma_addr_t addr,
> > }
> >
> > cached_entry = g_new0(SMMUTLBEntry, 1);
> > - status = smmu_ptw(cfg, aligned_addr, flag, cached_entry, info);
> > + status = smmu_ptw(cfg, aligned_addr, flag, cached_entry, info, bs);
> > if (status) {
> > g_free(cached_entry);
> > return NULL;
> > diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> > index 1db566d451..cf0fd3ec74 100644
> > --- a/include/hw/arm/smmu-common.h
> > +++ b/include/hw/arm/smmu-common.h
> > @@ -185,7 +185,7 @@ static inline uint16_t smmu_get_sid(SMMUDevice *sdev)
> > * pair, according to @cfg translation config
> > */
> > int smmu_ptw(SMMUTransCfg *cfg, dma_addr_t iova, IOMMUAccessFlags perm,
> > - SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info);
> > + SMMUTLBEntry *tlbe, SMMUPTWEventInfo *info, SMMUState *bs);
> >
> >
> > /*
> Thanks
>
> Eric
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 11/18] hw/arm/smmu: Support nesting in smmuv3_range_inval()
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (9 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 10/18] hw/arm/smmu-common: Support nested translation Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-04-29 3:23 ` [RFC PATCH v3 12/18] hw/arm/smmu: Support nesting in the rest of commands Mostafa Saleh
` (8 subsequent siblings)
19 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
With nesting, we would need to invalidate IPAs without
over-invalidating stage-1 IOVAs. This can be done by
distinguishing IPAs in the TLBs by having ASID=-1.
To achieve that, rework the invalidation for IPAs to have a
separate function, while for IOVA invalidation ASID=-1 means
invalidate for all ASIDs.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
hw/arm/smmu-common.c | 47 ++++++++++++++++++++++++++++++++++++
hw/arm/smmuv3.c | 23 ++++++++++++------
hw/arm/trace-events | 2 +-
include/hw/arm/smmu-common.h | 3 ++-
4 files changed, 66 insertions(+), 9 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index d48ec08947..fa2460cf64 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -183,6 +183,25 @@ static gboolean smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer value,
((entry->iova & ~info->mask) == info->iova);
}
+static gboolean smmu_hash_remove_by_vmid_ipa(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ SMMUTLBEntry *iter = (SMMUTLBEntry *)value;
+ IOMMUTLBEntry *entry = &iter->entry;
+ SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
+ SMMUIOTLBKey iotlb_key = *(SMMUIOTLBKey *)key;
+
+ if (info->asid >= 0) {
+ /* This is a stage-1 address. */
+ return false;
+ }
+ if (info->vmid != SMMU_IOTLB_VMID(iotlb_key)) {
+ return false;
+ }
+ return ((info->iova & ~entry->addr_mask) == entry->iova) ||
+ ((entry->iova & ~info->mask) == info->iova);
+}
+
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)
{
@@ -211,6 +230,34 @@ void smmu_iotlb_inv_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
&info);
}
+/*
+ * Similar to smmu_iotlb_inv_iova(), but for Stage-2, ASID is always -1,
+ * 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)
+{
+ 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);
+
+ if (g_hash_table_remove(s->iotlb, &key)) {
+ return;
+ }
+ }
+
+ SMMUIOTLBPageInvInfo info = {
+ .iova = ipa,
+ .vmid = vmid,
+ .mask = (num_pages * 1 << granule) - 1};
+
+ g_hash_table_foreach_remove(s->iotlb,
+ smmu_hash_remove_by_vmid_ipa,
+ &info);
+}
+
void smmu_iotlb_inv_asid(SMMUState *s, int asid)
{
trace_smmu_iotlb_inv_asid(asid);
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index cc61c82321..82d918d9b5 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1118,7 +1118,7 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
}
}
-static void smmuv3_range_inval(SMMUState *s, Cmd *cmd)
+static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
{
dma_addr_t end, addr = CMD_ADDR(cmd);
uint8_t type = CMD_TYPE(cmd);
@@ -1143,9 +1143,13 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd)
}
if (!tg) {
- trace_smmuv3_range_inval(vmid, asid, addr, tg, 1, ttl, leaf);
+ trace_smmuv3_range_inval(vmid, asid, addr, tg, 1, ttl, leaf, stage);
smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1);
- smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl);
+ if (stage == SMMU_STAGE_1) {
+ smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, 1, ttl);
+ } else {
+ smmu_iotlb_inv_ipa(s, vmid, addr, tg, 1, ttl);
+ }
return;
}
@@ -1161,9 +1165,14 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd)
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);
+ trace_smmuv3_range_inval(vmid, asid, addr, tg, num_pages,
+ ttl, leaf, stage);
smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, num_pages);
- smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, num_pages, ttl);
+ if (stage == SMMU_STAGE_1) {
+ smmu_iotlb_inv_iova(s, asid, vmid, addr, tg, num_pages, ttl);
+ } else {
+ smmu_iotlb_inv_ipa(s, vmid, addr, tg, num_pages, ttl);
+ }
addr += mask + 1;
}
}
@@ -1322,7 +1331,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
cmd_error = SMMU_CERROR_ILL;
break;
}
- smmuv3_range_inval(bs, &cmd);
+ smmuv3_range_inval(bs, &cmd, SMMU_STAGE_1);
break;
case SMMU_CMD_TLBI_S12_VMALL:
{
@@ -1347,7 +1356,7 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
* As currently only either s1 or s2 are supported
* we can reuse same function for s2.
*/
- smmuv3_range_inval(bs, &cmd);
+ smmuv3_range_inval(bs, &cmd, SMMU_STAGE_2);
break;
case SMMU_CMD_TLBI_EL3_ALL:
case SMMU_CMD_TLBI_EL3_VA:
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index 09ccd39548..7d9c1703da 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -46,7 +46,7 @@ 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) "vmid=%d asid=%d addr=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64" ttl=%d leaf=%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(void) ""
smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index cf0fd3ec74..de032fdfd1 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -216,7 +216,8 @@ void smmu_iotlb_inv_asid(SMMUState *s, int asid);
void smmu_iotlb_inv_vmid(SMMUState *s, int vmid);
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);
-
+void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
+ uint64_t num_pages, uint8_t ttl);
/* Unmap the range of all the notifiers registered to any IOMMU mr */
void smmu_inv_notifiers_all(SMMUState *s);
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* [RFC PATCH v3 12/18] hw/arm/smmu: Support nesting in the rest of commands
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (10 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 11/18] hw/arm/smmu: Support nesting in smmuv3_range_inval() Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-20 10:24 ` Eric Auger
2024-04-29 3:23 ` [RFC PATCH v3 13/18] hw/arm/smmuv3: Support nested SMMUs in smmuv3_notify_iova() Mostafa Saleh
` (7 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
Some commands need rework for nesting, as they used to assume S1
and S2 are mutually exclusive:
- CMD_TLBI_NH_ASID: Consider VMID if stage-2 is supported
- CMD_TLBI_NH_ALL: Consider VMID if stage-2 is supported, otherwise
invalidate everything, this required a new vmid invalidation
function for stage-1 only (ASID >= 0)
Also, rework trace events to reflect the new implementation.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmu-common.c | 36 +++++++++++++++++++++++++++++-------
hw/arm/smmuv3.c | 31 +++++++++++++++++++++++++++++--
hw/arm/trace-events | 6 ++++--
include/hw/arm/smmu-common.h | 3 ++-
4 files changed, 64 insertions(+), 12 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index fa2460cf64..3ed0be05ef 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -147,13 +147,14 @@ void smmu_iotlb_inv_all(SMMUState *s)
g_hash_table_remove_all(s->iotlb);
}
-static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
- gpointer user_data)
+static gboolean smmu_hash_remove_by_asid_vmid(gpointer key, gpointer value,
+ gpointer user_data)
{
- int asid = *(int *)user_data;
+ SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
- return SMMU_IOTLB_ASID(*iotlb_key) == asid;
+ return (SMMU_IOTLB_ASID(*iotlb_key) == info->asid) &&
+ (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid);
}
static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
@@ -165,6 +166,16 @@ static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
return SMMU_IOTLB_VMID(*iotlb_key) == vmid;
}
+static gboolean smmu_hash_remove_by_vmid_s1(gpointer key, gpointer value,
+ gpointer user_data)
+{
+ int vmid = *(int *)user_data;
+ SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
+
+ return (SMMU_IOTLB_VMID(*iotlb_key) == vmid) &&
+ (SMMU_IOTLB_ASID(*iotlb_key) >= 0);
+}
+
static gboolean smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer value,
gpointer user_data)
{
@@ -258,10 +269,15 @@ void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
&info);
}
-void smmu_iotlb_inv_asid(SMMUState *s, int asid)
+void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid)
{
- trace_smmu_iotlb_inv_asid(asid);
- g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
+ SMMUIOTLBPageInvInfo info = {
+ .asid = asid,
+ .vmid = vmid,
+ };
+
+ trace_smmu_iotlb_inv_asid_vmid(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)
@@ -270,6 +286,12 @@ void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
}
+inline void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
+{
+ trace_smmu_iotlb_inv_vmid_s1(vmid);
+ g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid_s1, &vmid);
+}
+
/* VMSAv8-64 Translation */
/**
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 82d918d9b5..e0fd494646 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1303,25 +1303,52 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
case SMMU_CMD_TLBI_NH_ASID:
{
int asid = CMD_ASID(&cmd);
+ int vmid = -1;
if (!STAGE1_SUPPORTED(s)) {
cmd_error = SMMU_CERROR_ILL;
break;
}
+ /*
+ * VMID is only matched when stage 2 is supported for the Security
+ * state corresponding to the command queue that the command was
+ * issued in.
+ * QEMU ignores the field by setting to -1, similarly to what STE
+ * decoding does. And invalidation commands ignore VMID < 0.
+ */
+ if (STAGE2_SUPPORTED(s)) {
+ vmid = CMD_VMID(&cmd);
+ }
+
trace_smmuv3_cmdq_tlbi_nh_asid(asid);
smmu_inv_notifiers_all(&s->smmu_state);
- smmu_iotlb_inv_asid(bs, asid);
+ smmu_iotlb_inv_asid_vmid(bs, asid, vmid);
break;
}
case SMMU_CMD_TLBI_NH_ALL:
+ {
+ int vmid = -1;
+
if (!STAGE1_SUPPORTED(s)) {
cmd_error = SMMU_CERROR_ILL;
break;
}
+
+ /*
+ * If stage-2 is supported, invalidate for this VMID only, otherwise
+ * invalidate the whole thing, see SMMU_CMD_TLBI_NH_ASID()
+ */
+ if (STAGE2_SUPPORTED(s)) {
+ vmid = CMD_VMID(&cmd);
+ trace_smmuv3_cmdq_tlbi_nh(vmid);
+ smmu_iotlb_inv_vmid_s1(bs, vmid);
+ break;
+ }
QEMU_FALLTHROUGH;
+ }
case SMMU_CMD_TLBI_NSNH_ALL:
- trace_smmuv3_cmdq_tlbi_nh();
+ trace_smmuv3_cmdq_tlbi_nsnh();
smmu_inv_notifiers_all(&s->smmu_state);
smmu_iotlb_inv_all(bs);
break;
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index 7d9c1703da..593cc571da 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -11,8 +11,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(int asid) "IOTLB invalidate asid=%d"
+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_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
smmu_inv_notifiers_mr(const char *name) "iommu mr=%s"
smmu_iotlb_lookup_hit(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
@@ -47,7 +48,8 @@ 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(void) ""
+smmuv3_cmdq_tlbi_nh(int vmid) "vmid=%d"
+smmuv3_cmdq_tlbi_nsnh(void) ""
smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
index de032fdfd1..361e639630 100644
--- a/include/hw/arm/smmu-common.h
+++ b/include/hw/arm/smmu-common.h
@@ -212,8 +212,9 @@ 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);
void smmu_iotlb_inv_all(SMMUState *s);
-void smmu_iotlb_inv_asid(SMMUState *s, int asid);
+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_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
uint8_t tg, uint64_t num_pages, uint8_t ttl);
void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 12/18] hw/arm/smmu: Support nesting in the rest of commands
2024-04-29 3:23 ` [RFC PATCH v3 12/18] hw/arm/smmu: Support nesting in the rest of commands Mostafa Saleh
@ 2024-05-20 10:24 ` Eric Auger
2024-06-17 14:58 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-20 10:24 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> Some commands need rework for nesting, as they used to assume S1
> and S2 are mutually exclusive:
>
> - CMD_TLBI_NH_ASID: Consider VMID if stage-2 is supported
> - CMD_TLBI_NH_ALL: Consider VMID if stage-2 is supported, otherwise
> invalidate everything, this required a new vmid invalidation
> function for stage-1 only (ASID >= 0)
>
> Also, rework trace events to reflect the new implementation.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmu-common.c | 36 +++++++++++++++++++++++++++++-------
> hw/arm/smmuv3.c | 31 +++++++++++++++++++++++++++++--
> hw/arm/trace-events | 6 ++++--
> include/hw/arm/smmu-common.h | 3 ++-
> 4 files changed, 64 insertions(+), 12 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index fa2460cf64..3ed0be05ef 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -147,13 +147,14 @@ void smmu_iotlb_inv_all(SMMUState *s)
> g_hash_table_remove_all(s->iotlb);
> }
>
> -static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
> - gpointer user_data)
> +static gboolean smmu_hash_remove_by_asid_vmid(gpointer key, gpointer value,
> + gpointer user_data)
Can't you introduce
smmu_hash_remove_by_asid_vmid() separately and replace the smmu_iotlb_inv_asid() call in SMMU_CMD_TLBI_NH_ASID.
Then you could focus on "if stage2 is supported" enhancements in this patch.
> {
> - int asid = *(int *)user_data;
> + SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
> SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
>
> - return SMMU_IOTLB_ASID(*iotlb_key) == asid;
> + return (SMMU_IOTLB_ASID(*iotlb_key) == info->asid) &&
> + (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid);
> }
>
> static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
> @@ -165,6 +166,16 @@ static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
> return SMMU_IOTLB_VMID(*iotlb_key) == vmid;
> }
>
> +static gboolean smmu_hash_remove_by_vmid_s1(gpointer key, gpointer value,
> + gpointer user_data)
> +{
> + int vmid = *(int *)user_data;
> + SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
> +
> + return (SMMU_IOTLB_VMID(*iotlb_key) == vmid) &&
> + (SMMU_IOTLB_ASID(*iotlb_key) >= 0);
> +}
> +
> static gboolean smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer value,
> gpointer user_data)
> {
> @@ -258,10 +269,15 @@ void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
> &info);
> }
>
> -void smmu_iotlb_inv_asid(SMMUState *s, int asid)
> +void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid)
> {
> - trace_smmu_iotlb_inv_asid(asid);
> - g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
> + SMMUIOTLBPageInvInfo info = {
> + .asid = asid,
> + .vmid = vmid,
> + };
> +
> + trace_smmu_iotlb_inv_asid_vmid(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)
> @@ -270,6 +286,12 @@ void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
> g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
> }
>
> +inline void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
> +{
> + trace_smmu_iotlb_inv_vmid_s1(vmid);
> + g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid_s1, &vmid);
> +}
> +
> /* VMSAv8-64 Translation */
>
> /**
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 82d918d9b5..e0fd494646 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1303,25 +1303,52 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
> case SMMU_CMD_TLBI_NH_ASID:
> {
> int asid = CMD_ASID(&cmd);
> + int vmid = -1;
>
> if (!STAGE1_SUPPORTED(s)) {
> cmd_error = SMMU_CERROR_ILL;
> break;
> }
>
> + /*
> + * VMID is only matched when stage 2 is supported for the Security
> + * state corresponding to the command queue that the command was
> + * issued in.
> + * QEMU ignores the field by setting to -1, similarly to what STE
> + * decoding does. And invalidation commands ignore VMID < 0.
> + */
> + if (STAGE2_SUPPORTED(s)) {
> + vmid = CMD_VMID(&cmd);
> + }
> +
> trace_smmuv3_cmdq_tlbi_nh_asid(asid);
> smmu_inv_notifiers_all(&s->smmu_state);
> - smmu_iotlb_inv_asid(bs, asid);
> + smmu_iotlb_inv_asid_vmid(bs, asid, vmid);
> break;
> }
> case SMMU_CMD_TLBI_NH_ALL:
> + {
> + int vmid = -1;
> +
> if (!STAGE1_SUPPORTED(s)) {
> cmd_error = SMMU_CERROR_ILL;
> break;
> }
> +
> + /*
> + * If stage-2 is supported, invalidate for this VMID only, otherwise
> + * invalidate the whole thing, see SMMU_CMD_TLBI_NH_ASID()
> + */
> + if (STAGE2_SUPPORTED(s)) {
> + vmid = CMD_VMID(&cmd);
> + trace_smmuv3_cmdq_tlbi_nh(vmid);
> + smmu_iotlb_inv_vmid_s1(bs, vmid);
> + break;
> + }
> QEMU_FALLTHROUGH;
> + }
> case SMMU_CMD_TLBI_NSNH_ALL:
> - trace_smmuv3_cmdq_tlbi_nh();
> + trace_smmuv3_cmdq_tlbi_nsnh();
> smmu_inv_notifiers_all(&s->smmu_state);
> smmu_iotlb_inv_all(bs);
> break;
> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> index 7d9c1703da..593cc571da 100644
> --- a/hw/arm/trace-events
> +++ b/hw/arm/trace-events
> @@ -11,8 +11,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(int asid) "IOTLB invalidate asid=%d"
> +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_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
> smmu_inv_notifiers_mr(const char *name) "iommu mr=%s"
> smmu_iotlb_lookup_hit(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
> @@ -47,7 +48,8 @@ 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(void) ""
> +smmuv3_cmdq_tlbi_nh(int vmid) "vmid=%d"
> +smmuv3_cmdq_tlbi_nsnh(void) ""
> smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
> smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
> smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
> diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> index de032fdfd1..361e639630 100644
> --- a/include/hw/arm/smmu-common.h
> +++ b/include/hw/arm/smmu-common.h
> @@ -212,8 +212,9 @@ 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);
> void smmu_iotlb_inv_all(SMMUState *s);
> -void smmu_iotlb_inv_asid(SMMUState *s, int asid);
> +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_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> uint8_t tg, uint64_t num_pages, uint8_t ttl);
> void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
Otherwise looks good to me
Eric
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 12/18] hw/arm/smmu: Support nesting in the rest of commands
2024-05-20 10:24 ` Eric Auger
@ 2024-06-17 14:58 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-06-17 14:58 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Mon, May 20, 2024 at 12:24:22PM +0200, Eric Auger wrote:
> Hi Mostafa,
>
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > Some commands need rework for nesting, as they used to assume S1
> > and S2 are mutually exclusive:
> >
> > - CMD_TLBI_NH_ASID: Consider VMID if stage-2 is supported
> > - CMD_TLBI_NH_ALL: Consider VMID if stage-2 is supported, otherwise
> > invalidate everything, this required a new vmid invalidation
> > function for stage-1 only (ASID >= 0)
> >
> > Also, rework trace events to reflect the new implementation.
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmu-common.c | 36 +++++++++++++++++++++++++++++-------
> > hw/arm/smmuv3.c | 31 +++++++++++++++++++++++++++++--
> > hw/arm/trace-events | 6 ++++--
> > include/hw/arm/smmu-common.h | 3 ++-
> > 4 files changed, 64 insertions(+), 12 deletions(-)
> >
> > diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> > index fa2460cf64..3ed0be05ef 100644
> > --- a/hw/arm/smmu-common.c
> > +++ b/hw/arm/smmu-common.c
> > @@ -147,13 +147,14 @@ void smmu_iotlb_inv_all(SMMUState *s)
> > g_hash_table_remove_all(s->iotlb);
> > }
> >
> > -static gboolean smmu_hash_remove_by_asid(gpointer key, gpointer value,
> > - gpointer user_data)
> > +static gboolean smmu_hash_remove_by_asid_vmid(gpointer key, gpointer value,
> > + gpointer user_data)
> Can't you introduce
>
> smmu_hash_remove_by_asid_vmid() separately and replace the smmu_iotlb_inv_asid() call in SMMU_CMD_TLBI_NH_ASID.
> Then you could focus on "if stage2 is supported" enhancements in this patch.
>
Sure, will do.
Thanks,
Mostafa
> > {
> > - int asid = *(int *)user_data;
> > + SMMUIOTLBPageInvInfo *info = (SMMUIOTLBPageInvInfo *)user_data;
> > SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
> >
> > - return SMMU_IOTLB_ASID(*iotlb_key) == asid;
> > + return (SMMU_IOTLB_ASID(*iotlb_key) == info->asid) &&
> > + (SMMU_IOTLB_VMID(*iotlb_key) == info->vmid);
> > }
> >
> > static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
> > @@ -165,6 +166,16 @@ static gboolean smmu_hash_remove_by_vmid(gpointer key, gpointer value,
> > return SMMU_IOTLB_VMID(*iotlb_key) == vmid;
> > }
> >
> > +static gboolean smmu_hash_remove_by_vmid_s1(gpointer key, gpointer value,
> > + gpointer user_data)
> > +{
> > + int vmid = *(int *)user_data;
> > + SMMUIOTLBKey *iotlb_key = (SMMUIOTLBKey *)key;
> > +
> > + return (SMMU_IOTLB_VMID(*iotlb_key) == vmid) &&
> > + (SMMU_IOTLB_ASID(*iotlb_key) >= 0);
> > +}
> > +
> > static gboolean smmu_hash_remove_by_asid_vmid_iova(gpointer key, gpointer value,
> > gpointer user_data)
> > {
> > @@ -258,10 +269,15 @@ void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
> > &info);
> > }
> >
> > -void smmu_iotlb_inv_asid(SMMUState *s, int asid)
> > +void smmu_iotlb_inv_asid_vmid(SMMUState *s, int asid, int vmid)
> > {
> > - trace_smmu_iotlb_inv_asid(asid);
> > - g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_asid, &asid);
> > + SMMUIOTLBPageInvInfo info = {
> > + .asid = asid,
> > + .vmid = vmid,
> > + };
> > +
> > + trace_smmu_iotlb_inv_asid_vmid(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)
> > @@ -270,6 +286,12 @@ void smmu_iotlb_inv_vmid(SMMUState *s, int vmid)
> > g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid, &vmid);
> > }
> >
> > +inline void smmu_iotlb_inv_vmid_s1(SMMUState *s, int vmid)
> > +{
> > + trace_smmu_iotlb_inv_vmid_s1(vmid);
> > + g_hash_table_foreach_remove(s->iotlb, smmu_hash_remove_by_vmid_s1, &vmid);
> > +}
> > +
> > /* VMSAv8-64 Translation */
> >
> > /**
> > diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> > index 82d918d9b5..e0fd494646 100644
> > --- a/hw/arm/smmuv3.c
> > +++ b/hw/arm/smmuv3.c
> > @@ -1303,25 +1303,52 @@ static int smmuv3_cmdq_consume(SMMUv3State *s)
> > case SMMU_CMD_TLBI_NH_ASID:
> > {
> > int asid = CMD_ASID(&cmd);
> > + int vmid = -1;
> >
> > if (!STAGE1_SUPPORTED(s)) {
> > cmd_error = SMMU_CERROR_ILL;
> > break;
> > }
> >
> > + /*
> > + * VMID is only matched when stage 2 is supported for the Security
> > + * state corresponding to the command queue that the command was
> > + * issued in.
> > + * QEMU ignores the field by setting to -1, similarly to what STE
> > + * decoding does. And invalidation commands ignore VMID < 0.
> > + */
> > + if (STAGE2_SUPPORTED(s)) {
> > + vmid = CMD_VMID(&cmd);
> > + }
> > +
> > trace_smmuv3_cmdq_tlbi_nh_asid(asid);
> > smmu_inv_notifiers_all(&s->smmu_state);
> > - smmu_iotlb_inv_asid(bs, asid);
> > + smmu_iotlb_inv_asid_vmid(bs, asid, vmid);
> > break;
> > }
> > case SMMU_CMD_TLBI_NH_ALL:
> > + {
> > + int vmid = -1;
> > +
> > if (!STAGE1_SUPPORTED(s)) {
> > cmd_error = SMMU_CERROR_ILL;
> > break;
> > }
> > +
> > + /*
> > + * If stage-2 is supported, invalidate for this VMID only, otherwise
> > + * invalidate the whole thing, see SMMU_CMD_TLBI_NH_ASID()
> > + */
> > + if (STAGE2_SUPPORTED(s)) {
> > + vmid = CMD_VMID(&cmd);
> > + trace_smmuv3_cmdq_tlbi_nh(vmid);
> > + smmu_iotlb_inv_vmid_s1(bs, vmid);
> > + break;
> > + }
> > QEMU_FALLTHROUGH;
> > + }
> > case SMMU_CMD_TLBI_NSNH_ALL:
> > - trace_smmuv3_cmdq_tlbi_nh();
> > + trace_smmuv3_cmdq_tlbi_nsnh();
> > smmu_inv_notifiers_all(&s->smmu_state);
> > smmu_iotlb_inv_all(bs);
> > break;
> > diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> > index 7d9c1703da..593cc571da 100644
> > --- a/hw/arm/trace-events
> > +++ b/hw/arm/trace-events
> > @@ -11,8 +11,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(int asid) "IOTLB invalidate asid=%d"
> > +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_iova(int asid, uint64_t addr) "IOTLB invalidate asid=%d addr=0x%"PRIx64
> > smmu_inv_notifiers_mr(const char *name) "iommu mr=%s"
> > smmu_iotlb_lookup_hit(int asid, int vmid, uint64_t addr, uint32_t hit, uint32_t miss, uint32_t p) "IOTLB cache HIT asid=%d vmid=%d addr=0x%"PRIx64" hit=%d miss=%d hit rate=%d"
> > @@ -47,7 +48,8 @@ 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(void) ""
> > +smmuv3_cmdq_tlbi_nh(int vmid) "vmid=%d"
> > +smmuv3_cmdq_tlbi_nsnh(void) ""
> > smmuv3_cmdq_tlbi_nh_asid(int asid) "asid=%d"
> > smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
> > smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
> > diff --git a/include/hw/arm/smmu-common.h b/include/hw/arm/smmu-common.h
> > index de032fdfd1..361e639630 100644
> > --- a/include/hw/arm/smmu-common.h
> > +++ b/include/hw/arm/smmu-common.h
> > @@ -212,8 +212,9 @@ 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);
> > void smmu_iotlb_inv_all(SMMUState *s);
> > -void smmu_iotlb_inv_asid(SMMUState *s, int asid);
> > +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_iova(SMMUState *s, int asid, int vmid, dma_addr_t iova,
> > uint8_t tg, uint64_t num_pages, uint8_t ttl);
> > void smmu_iotlb_inv_ipa(SMMUState *s, int vmid, dma_addr_t ipa, uint8_t tg,
> Otherwise looks good to me
>
> Eric
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 13/18] hw/arm/smmuv3: Support nested SMMUs in smmuv3_notify_iova()
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (11 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 12/18] hw/arm/smmu: Support nesting in the rest of commands Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-20 10:37 ` Eric Auger
2024-04-29 3:23 ` [RFC PATCH v3 14/18] hw/arm/smmuv3: Support and advertise nesting Mostafa Saleh
` (6 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
IOMMUTLBEvent only understands IOVA, for stage-2 only SMMUs keep
the implementation, while only notify for stage-1 invalidation
in case of nesting.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmuv3.c | 23 +++++++++++++++--------
hw/arm/trace-events | 2 +-
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index e0fd494646..96d07234fe 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -1051,7 +1051,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
IOMMUNotifier *n,
int asid, int vmid,
dma_addr_t iova, uint8_t tg,
- uint64_t num_pages)
+ uint64_t num_pages, int stage)
{
SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
IOMMUTLBEvent event;
@@ -1075,14 +1075,21 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
return;
}
- if (STAGE1_SUPPORTED(s)) {
+ /*
+ * IOMMUTLBEvent only understands IOVA, for stage-2 only SMMUs
+ * keep the implementation, while only notify for stage-1
+ * invalidation in case of nesting.
+ */
+ if (stage == SMMU_STAGE_1) {
tt = select_tt(cfg, iova);
if (!tt) {
return;
}
granule = tt->granule_sz;
- } else {
+ } else if (!STAGE1_SUPPORTED(s)) {
granule = cfg->s2cfg.granule_sz;
+ } else {
+ return;
}
} else {
@@ -1101,7 +1108,7 @@ 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)
+ uint64_t num_pages, int stage)
{
SMMUDevice *sdev;
@@ -1110,10 +1117,10 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
IOMMUNotifier *n;
trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, vmid,
- iova, tg, num_pages);
+ iova, tg, num_pages, stage);
IOMMU_NOTIFIER_FOREACH(n, mr) {
- smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages);
+ smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages, stage);
}
}
}
@@ -1144,7 +1151,7 @@ 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);
- smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1);
+ 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);
} else {
@@ -1167,7 +1174,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
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);
+ 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);
} else {
diff --git a/hw/arm/trace-events b/hw/arm/trace-events
index 593cc571da..be6c8f720b 100644
--- a/hw/arm/trace-events
+++ b/hw/arm/trace-events
@@ -55,7 +55,7 @@ smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
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) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
+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"
# strongarm.c
strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d"
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 13/18] hw/arm/smmuv3: Support nested SMMUs in smmuv3_notify_iova()
2024-04-29 3:23 ` [RFC PATCH v3 13/18] hw/arm/smmuv3: Support nested SMMUs in smmuv3_notify_iova() Mostafa Saleh
@ 2024-05-20 10:37 ` Eric Auger
2024-06-17 15:02 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-20 10:37 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> IOMMUTLBEvent only understands IOVA, for stage-2 only SMMUs keep
> the implementation, while only notify for stage-1 invalidation
> in case of nesting.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmuv3.c | 23 +++++++++++++++--------
> hw/arm/trace-events | 2 +-
> 2 files changed, 16 insertions(+), 9 deletions(-)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index e0fd494646..96d07234fe 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -1051,7 +1051,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> IOMMUNotifier *n,
> int asid, int vmid,
> dma_addr_t iova, uint8_t tg,
> - uint64_t num_pages)
> + uint64_t num_pages, int stage)
add the new param in the doc comment above
> {
> SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
> IOMMUTLBEvent event;
> @@ -1075,14 +1075,21 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> return;
> }
>
> - if (STAGE1_SUPPORTED(s)) {
> + /*
> + * IOMMUTLBEvent only understands IOVA, for stage-2 only SMMUs
> + * keep the implementation, while only notify for stage-1
> + * invalidation in case of nesting.
> + */
> + if (stage == SMMU_STAGE_1) {
> tt = select_tt(cfg, iova);
> if (!tt) {
> return;
> }
> granule = tt->granule_sz;
> - } else {
> + } else if (!STAGE1_SUPPORTED(s)) {
I don't get why you don't test stage == SMMU_STAGE_2 instead
in each block shouldn't you test if the corresponding state of supported?
> granule = cfg->s2cfg.granule_sz;
> + } else {
I don't really understand the logic here. Please can you comment each case?
Thanks
Eric
> + return;
> }
>
> } else {
> @@ -1101,7 +1108,7 @@ 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)
> + uint64_t num_pages, int stage)
> {
> SMMUDevice *sdev;
>
> @@ -1110,10 +1117,10 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
> IOMMUNotifier *n;
>
> trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, vmid,
> - iova, tg, num_pages);
> + iova, tg, num_pages, stage);
>
> IOMMU_NOTIFIER_FOREACH(n, mr) {
> - smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages);
> + smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages, stage);
> }
> }
> }
> @@ -1144,7 +1151,7 @@ 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);
> - smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1);
> + 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);
> } else {
> @@ -1167,7 +1174,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
> 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);
> + 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);
> } else {
> diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> index 593cc571da..be6c8f720b 100644
> --- a/hw/arm/trace-events
> +++ b/hw/arm/trace-events
> @@ -55,7 +55,7 @@ smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
> smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
> 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) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
> +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"
>
> # strongarm.c
> strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d"
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 13/18] hw/arm/smmuv3: Support nested SMMUs in smmuv3_notify_iova()
2024-05-20 10:37 ` Eric Auger
@ 2024-06-17 15:02 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-06-17 15:02 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Mon, May 20, 2024 at 12:37:55PM +0200, Eric Auger wrote:
> Hi Mostafa,
>
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > IOMMUTLBEvent only understands IOVA, for stage-2 only SMMUs keep
> > the implementation, while only notify for stage-1 invalidation
> > in case of nesting.
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmuv3.c | 23 +++++++++++++++--------
> > hw/arm/trace-events | 2 +-
> > 2 files changed, 16 insertions(+), 9 deletions(-)
> >
> > diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> > index e0fd494646..96d07234fe 100644
> > --- a/hw/arm/smmuv3.c
> > +++ b/hw/arm/smmuv3.c
> > @@ -1051,7 +1051,7 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> > IOMMUNotifier *n,
> > int asid, int vmid,
> > dma_addr_t iova, uint8_t tg,
> > - uint64_t num_pages)
> > + uint64_t num_pages, int stage)
> add the new param in the doc comment above
> > {
> > SMMUDevice *sdev = container_of(mr, SMMUDevice, iommu);
> > IOMMUTLBEvent event;
> > @@ -1075,14 +1075,21 @@ static void smmuv3_notify_iova(IOMMUMemoryRegion *mr,
> > return;
> > }
> >
> > - if (STAGE1_SUPPORTED(s)) {
> > + /*
> > + * IOMMUTLBEvent only understands IOVA, for stage-2 only SMMUs
> > + * keep the implementation, while only notify for stage-1
> > + * invalidation in case of nesting.
> > + */
> > + if (stage == SMMU_STAGE_1) {
> > tt = select_tt(cfg, iova);
> > if (!tt) {
> > return;
> > }
> > granule = tt->granule_sz;
> > - } else {
> > + } else if (!STAGE1_SUPPORTED(s)) {
> I don't get why you don't test stage == SMMU_STAGE_2 instead
> in each block shouldn't you test if the corresponding state of supported?
> > granule = cfg->s2cfg.granule_sz;
> > + } else {
> I don't really understand the logic here. Please can you comment each case?
The current implementation will call memory_region_notify_iommu_one()
from smmuv3_notify_iova() for stage-1 or stage-2 based on which one is supported
and in each case this address is considered an “IOVA”.
However, with nested translation memory_region_notify_iommu_one() doesn’t distinguish
between stage-1 and stage-2, so only stage-1 is considered “IOVA”.
And the implementation basically as follows:
1) If the translation was stage-1, it’s an IOVA and
memory_region_notify_iommu_one() is called.
2) If stage-1 is not supported (this is an stage-2 only instance) maintain
the old behaviour by calling memory_region_notify_iommu_one()
3) This leaves us with stage-1 being supported and this is a stage-2
translation, where the notification would be ignored, I think in
this case if the SW configured only for stage-2 it would expect
it to behave as 2) :/
Not sure how to fix that, maybe only ignore stage-2 if it was in a nested STE,
or just or always ignore stage-2?
Thanks,
Mostafa
>
> Thanks
>
> Eric
> > + return;
> > }
> >
> > } else {
> > @@ -1101,7 +1108,7 @@ 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)
> > + uint64_t num_pages, int stage)
> > {
> > SMMUDevice *sdev;
> >
> > @@ -1110,10 +1117,10 @@ static void smmuv3_inv_notifiers_iova(SMMUState *s, int asid, int vmid,
> > IOMMUNotifier *n;
> >
> > trace_smmuv3_inv_notifiers_iova(mr->parent_obj.name, asid, vmid,
> > - iova, tg, num_pages);
> > + iova, tg, num_pages, stage);
> >
> > IOMMU_NOTIFIER_FOREACH(n, mr) {
> > - smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages);
> > + smmuv3_notify_iova(mr, n, asid, vmid, iova, tg, num_pages, stage);
> > }
> > }
> > }
> > @@ -1144,7 +1151,7 @@ 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);
> > - smmuv3_inv_notifiers_iova(s, asid, vmid, addr, tg, 1);
> > + 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);
> > } else {
> > @@ -1167,7 +1174,7 @@ static void smmuv3_range_inval(SMMUState *s, Cmd *cmd, SMMUStage stage)
> > 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);
> > + 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);
> > } else {
> > diff --git a/hw/arm/trace-events b/hw/arm/trace-events
> > index 593cc571da..be6c8f720b 100644
> > --- a/hw/arm/trace-events
> > +++ b/hw/arm/trace-events
> > @@ -55,7 +55,7 @@ smmuv3_cmdq_tlbi_s12_vmid(int vmid) "vmid=%d"
> > smmuv3_config_cache_inv(uint32_t sid) "Config cache INV for sid=0x%x"
> > 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) "iommu mr=%s asid=%d vmid=%d iova=0x%"PRIx64" tg=%d num_pages=0x%"PRIx64
> > +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"
> >
> > # strongarm.c
> > strongarm_uart_update_parameters(const char *label, int speed, char parity, int data_bits, int stop_bits) "%s speed=%d parity=%c data=%d stop=%d"
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 14/18] hw/arm/smmuv3: Support and advertise nesting
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (12 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 13/18] hw/arm/smmuv3: Support nested SMMUs in smmuv3_notify_iova() Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-20 13:16 ` Eric Auger
2024-04-29 3:23 ` [RFC PATCH v3 15/18] hw/arm/smmuv3: Advertise S2FWB Mostafa Saleh
` (5 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
Everything is in place, add the last missing bits:
- Handle fault checking according to the actual PTW event and not the
the translation stage.
- Consolidate parsing of STE cfg and setting translation stage.
Advertise nesting if stage requested is "nested".
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmuv3.c | 50 +++++++++++++++++++++++++++++++++----------------
1 file changed, 34 insertions(+), 16 deletions(-)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 96d07234fe..88f6473d33 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -34,9 +34,10 @@
#include "smmuv3-internal.h"
#include "smmu-internal.h"
-#define PTW_RECORD_FAULT(cfg) (((cfg)->stage == SMMU_STAGE_1) ? \
- (cfg)->record_faults : \
- (cfg)->s2cfg.record_faults)
+#define PTW_RECORD_FAULT(ptw_info, cfg) (((ptw_info).stage == SMMU_STAGE_1 && \
+ (cfg)->record_faults) || \
+ ((ptw_info).stage == SMMU_STAGE_2 && \
+ (cfg)->s2cfg.record_faults))
/**
* smmuv3_trigger_irq - pulse @irq if enabled and update
@@ -260,6 +261,9 @@ static void smmuv3_init_regs(SMMUv3State *s)
/* 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);
+ } 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);
} else {
s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S1P, 1);
}
@@ -422,8 +426,6 @@ static bool s2_pgtable_config_valid(uint8_t sl0, uint8_t t0sz, uint8_t gran)
static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
{
- cfg->stage = SMMU_STAGE_2;
-
if (STE_S2AA64(ste) == 0x0) {
qemu_log_mask(LOG_UNIMP,
"SMMUv3 AArch32 tables not supported\n");
@@ -506,6 +508,27 @@ bad_ste:
return -EINVAL;
}
+static void decode_ste_config(SMMUTransCfg *cfg, uint32_t config)
+{
+
+ if (STE_CFG_ABORT(config)) {
+ cfg->aborted = true;
+ return;
+ }
+ if (STE_CFG_BYPASS(config)) {
+ cfg->bypassed = true;
+ return;
+ }
+
+ if (STE_CFG_S1_ENABLED(config)) {
+ cfg->stage = SMMU_STAGE_1;
+ }
+
+ if (STE_CFG_S2_ENABLED(config)) {
+ cfg->stage |= SMMU_STAGE_2;
+ }
+}
+
/* Returns < 0 in case of invalid STE, 0 otherwise */
static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
STE *ste, SMMUEventInfo *event)
@@ -522,13 +545,9 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
config = STE_CONFIG(ste);
- if (STE_CFG_ABORT(config)) {
- cfg->aborted = true;
- return 0;
- }
+ decode_ste_config(cfg, config);
- if (STE_CFG_BYPASS(config)) {
- cfg->bypassed = true;
+ if (cfg->aborted || cfg->bypassed) {
return 0;
}
@@ -701,7 +720,6 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
/* we support only those at the moment */
cfg->aa64 = true;
- cfg->stage = SMMU_STAGE_1;
cfg->oas = oas2bits(CD_IPS(cd));
cfg->oas = MIN(oas2bits(SMMU_IDR5_OAS), cfg->oas);
@@ -901,7 +919,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
event->u.f_walk_eabt.addr2 = ptw_info.addr;
break;
case SMMU_PTW_ERR_TRANSLATION:
- if (PTW_RECORD_FAULT(cfg)) {
+ if (PTW_RECORD_FAULT(ptw_info, cfg)) {
event->type = SMMU_EVT_F_TRANSLATION;
event->u.f_translation.addr = addr;
event->u.f_translation.addr2 = ptw_info.addr;
@@ -910,7 +928,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
}
break;
case SMMU_PTW_ERR_ADDR_SIZE:
- if (PTW_RECORD_FAULT(cfg)) {
+ if (PTW_RECORD_FAULT(ptw_info, cfg)) {
event->type = SMMU_EVT_F_ADDR_SIZE;
event->u.f_addr_size.addr = addr;
event->u.f_addr_size.addr2 = ptw_info.addr;
@@ -919,7 +937,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
}
break;
case SMMU_PTW_ERR_ACCESS:
- if (PTW_RECORD_FAULT(cfg)) {
+ if (PTW_RECORD_FAULT(ptw_info, cfg)) {
event->type = SMMU_EVT_F_ACCESS;
event->u.f_access.addr = addr;
event->u.f_access.addr2 = ptw_info.addr;
@@ -928,7 +946,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
}
break;
case SMMU_PTW_ERR_PERMISSION:
- if (PTW_RECORD_FAULT(cfg)) {
+ if (PTW_RECORD_FAULT(ptw_info, cfg)) {
event->type = SMMU_EVT_F_PERMISSION;
event->u.f_permission.addr = addr;
event->u.f_permission.addr2 = ptw_info.addr;
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 14/18] hw/arm/smmuv3: Support and advertise nesting
2024-04-29 3:23 ` [RFC PATCH v3 14/18] hw/arm/smmuv3: Support and advertise nesting Mostafa Saleh
@ 2024-05-20 13:16 ` Eric Auger
2024-06-17 15:03 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-20 13:16 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> Everything is in place, add the last missing bits:
> - Handle fault checking according to the actual PTW event and not the
> the translation stage.
missing the "why". Can't it be moved in a separate patch?
> - Consolidate parsing of STE cfg and setting translation stage.
>
> Advertise nesting if stage requested is "nested".
I would move the introduction of the nested option in a separate patch
and in the associated commit msg properly document how the new option
shall be used.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmuv3.c | 50 +++++++++++++++++++++++++++++++++----------------
> 1 file changed, 34 insertions(+), 16 deletions(-)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 96d07234fe..88f6473d33 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -34,9 +34,10 @@
> #include "smmuv3-internal.h"
> #include "smmu-internal.h"
>
> -#define PTW_RECORD_FAULT(cfg) (((cfg)->stage == SMMU_STAGE_1) ? \
> - (cfg)->record_faults : \
> - (cfg)->s2cfg.record_faults)
> +#define PTW_RECORD_FAULT(ptw_info, cfg) (((ptw_info).stage == SMMU_STAGE_1 && \
> + (cfg)->record_faults) || \
> + ((ptw_info).stage == SMMU_STAGE_2 && \
> + (cfg)->s2cfg.record_faults))
>
> /**
> * smmuv3_trigger_irq - pulse @irq if enabled and update
> @@ -260,6 +261,9 @@ static void smmuv3_init_regs(SMMUv3State *s)
> /* 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);
> + } 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);
> } else {
> s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S1P, 1);
> }
> @@ -422,8 +426,6 @@ static bool s2_pgtable_config_valid(uint8_t sl0, uint8_t t0sz, uint8_t gran)
>
> static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
> {
> - cfg->stage = SMMU_STAGE_2;
> -
> if (STE_S2AA64(ste) == 0x0) {
> qemu_log_mask(LOG_UNIMP,
> "SMMUv3 AArch32 tables not supported\n");
> @@ -506,6 +508,27 @@ bad_ste:
> return -EINVAL;
> }
>
> +static void decode_ste_config(SMMUTransCfg *cfg, uint32_t config)
> +{
> +
> + if (STE_CFG_ABORT(config)) {
> + cfg->aborted = true;
> + return;
> + }
> + if (STE_CFG_BYPASS(config)) {
> + cfg->bypassed = true;
> + return;
> + }
> +
> + if (STE_CFG_S1_ENABLED(config)) {
> + cfg->stage = SMMU_STAGE_1;
> + }
> +
> + if (STE_CFG_S2_ENABLED(config)) {
> + cfg->stage |= SMMU_STAGE_2;
> + }
> +}
> +
> /* Returns < 0 in case of invalid STE, 0 otherwise */
> static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
> STE *ste, SMMUEventInfo *event)
> @@ -522,13 +545,9 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
>
> config = STE_CONFIG(ste);
>
> - if (STE_CFG_ABORT(config)) {
> - cfg->aborted = true;
> - return 0;
> - }
> + decode_ste_config(cfg, config);
>
> - if (STE_CFG_BYPASS(config)) {
> - cfg->bypassed = true;
> + if (cfg->aborted || cfg->bypassed) {
> return 0;
> }
>
> @@ -701,7 +720,6 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
>
> /* we support only those at the moment */
> cfg->aa64 = true;
> - cfg->stage = SMMU_STAGE_1;
>
> cfg->oas = oas2bits(CD_IPS(cd));
> cfg->oas = MIN(oas2bits(SMMU_IDR5_OAS), cfg->oas);
> @@ -901,7 +919,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> event->u.f_walk_eabt.addr2 = ptw_info.addr;
> break;
> case SMMU_PTW_ERR_TRANSLATION:
> - if (PTW_RECORD_FAULT(cfg)) {
> + if (PTW_RECORD_FAULT(ptw_info, cfg)) {
> event->type = SMMU_EVT_F_TRANSLATION;
> event->u.f_translation.addr = addr;
> event->u.f_translation.addr2 = ptw_info.addr;
> @@ -910,7 +928,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> }
> break;
> case SMMU_PTW_ERR_ADDR_SIZE:
> - if (PTW_RECORD_FAULT(cfg)) {
> + if (PTW_RECORD_FAULT(ptw_info, cfg)) {
> event->type = SMMU_EVT_F_ADDR_SIZE;
> event->u.f_addr_size.addr = addr;
> event->u.f_addr_size.addr2 = ptw_info.addr;
> @@ -919,7 +937,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> }
> break;
> case SMMU_PTW_ERR_ACCESS:
> - if (PTW_RECORD_FAULT(cfg)) {
> + if (PTW_RECORD_FAULT(ptw_info, cfg)) {
> event->type = SMMU_EVT_F_ACCESS;
> event->u.f_access.addr = addr;
> event->u.f_access.addr2 = ptw_info.addr;
> @@ -928,7 +946,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> }
> break;
> case SMMU_PTW_ERR_PERMISSION:
> - if (PTW_RECORD_FAULT(cfg)) {
> + if (PTW_RECORD_FAULT(ptw_info, cfg)) {
> event->type = SMMU_EVT_F_PERMISSION;
> event->u.f_permission.addr = addr;
> event->u.f_permission.addr2 = ptw_info.addr;
Thanks
Eric
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 14/18] hw/arm/smmuv3: Support and advertise nesting
2024-05-20 13:16 ` Eric Auger
@ 2024-06-17 15:03 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-06-17 15:03 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Mon, May 20, 2024 at 03:16:40PM +0200, Eric Auger wrote:
> Hi Mostafa,
>
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > Everything is in place, add the last missing bits:
> > - Handle fault checking according to the actual PTW event and not the
> > the translation stage.
> missing the "why". Can't it be moved in a separate patch?
Sure, I will split.
Thanks,
Mostafa
> > - Consolidate parsing of STE cfg and setting translation stage.
> >
> > Advertise nesting if stage requested is "nested".
> I would move the introduction of the nested option in a separate patch
> and in the associated commit msg properly document how the new option
> shall be used.
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmuv3.c | 50 +++++++++++++++++++++++++++++++++----------------
> > 1 file changed, 34 insertions(+), 16 deletions(-)
> >
> > diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> > index 96d07234fe..88f6473d33 100644
> > --- a/hw/arm/smmuv3.c
> > +++ b/hw/arm/smmuv3.c
> > @@ -34,9 +34,10 @@
> > #include "smmuv3-internal.h"
> > #include "smmu-internal.h"
> >
> > -#define PTW_RECORD_FAULT(cfg) (((cfg)->stage == SMMU_STAGE_1) ? \
> > - (cfg)->record_faults : \
> > - (cfg)->s2cfg.record_faults)
> > +#define PTW_RECORD_FAULT(ptw_info, cfg) (((ptw_info).stage == SMMU_STAGE_1 && \
> > + (cfg)->record_faults) || \
> > + ((ptw_info).stage == SMMU_STAGE_2 && \
> > + (cfg)->s2cfg.record_faults))
> >
> > /**
> > * smmuv3_trigger_irq - pulse @irq if enabled and update
> > @@ -260,6 +261,9 @@ static void smmuv3_init_regs(SMMUv3State *s)
> > /* 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);
> > + } 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);
> > } else {
> > s->idr[0] = FIELD_DP32(s->idr[0], IDR0, S1P, 1);
> > }
> > @@ -422,8 +426,6 @@ static bool s2_pgtable_config_valid(uint8_t sl0, uint8_t t0sz, uint8_t gran)
> >
> > static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
> > {
> > - cfg->stage = SMMU_STAGE_2;
> > -
> > if (STE_S2AA64(ste) == 0x0) {
> > qemu_log_mask(LOG_UNIMP,
> > "SMMUv3 AArch32 tables not supported\n");
> > @@ -506,6 +508,27 @@ bad_ste:
> > return -EINVAL;
> > }
> >
> > +static void decode_ste_config(SMMUTransCfg *cfg, uint32_t config)
> > +{
> > +
> > + if (STE_CFG_ABORT(config)) {
> > + cfg->aborted = true;
> > + return;
> > + }
> > + if (STE_CFG_BYPASS(config)) {
> > + cfg->bypassed = true;
> > + return;
> > + }
> > +
> > + if (STE_CFG_S1_ENABLED(config)) {
> > + cfg->stage = SMMU_STAGE_1;
> > + }
> > +
> > + if (STE_CFG_S2_ENABLED(config)) {
> > + cfg->stage |= SMMU_STAGE_2;
> > + }
> > +}
> > +
> > /* Returns < 0 in case of invalid STE, 0 otherwise */
> > static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
> > STE *ste, SMMUEventInfo *event)
> > @@ -522,13 +545,9 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
> >
> > config = STE_CONFIG(ste);
> >
> > - if (STE_CFG_ABORT(config)) {
> > - cfg->aborted = true;
> > - return 0;
> > - }
> > + decode_ste_config(cfg, config);
> >
> > - if (STE_CFG_BYPASS(config)) {
> > - cfg->bypassed = true;
> > + if (cfg->aborted || cfg->bypassed) {
> > return 0;
> > }
> >
> > @@ -701,7 +720,6 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
> >
> > /* we support only those at the moment */
> > cfg->aa64 = true;
> > - cfg->stage = SMMU_STAGE_1;
> >
> > cfg->oas = oas2bits(CD_IPS(cd));
> > cfg->oas = MIN(oas2bits(SMMU_IDR5_OAS), cfg->oas);
> > @@ -901,7 +919,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> > event->u.f_walk_eabt.addr2 = ptw_info.addr;
> > break;
> > case SMMU_PTW_ERR_TRANSLATION:
> > - if (PTW_RECORD_FAULT(cfg)) {
> > + if (PTW_RECORD_FAULT(ptw_info, cfg)) {
> > event->type = SMMU_EVT_F_TRANSLATION;
> > event->u.f_translation.addr = addr;
> > event->u.f_translation.addr2 = ptw_info.addr;
> > @@ -910,7 +928,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> > }
> > break;
> > case SMMU_PTW_ERR_ADDR_SIZE:
> > - if (PTW_RECORD_FAULT(cfg)) {
> > + if (PTW_RECORD_FAULT(ptw_info, cfg)) {
> > event->type = SMMU_EVT_F_ADDR_SIZE;
> > event->u.f_addr_size.addr = addr;
> > event->u.f_addr_size.addr2 = ptw_info.addr;
> > @@ -919,7 +937,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> > }
> > break;
> > case SMMU_PTW_ERR_ACCESS:
> > - if (PTW_RECORD_FAULT(cfg)) {
> > + if (PTW_RECORD_FAULT(ptw_info, cfg)) {
> > event->type = SMMU_EVT_F_ACCESS;
> > event->u.f_access.addr = addr;
> > event->u.f_access.addr2 = ptw_info.addr;
> > @@ -928,7 +946,7 @@ static SMMUTranslationStatus smmuv3_do_translate(SMMUv3State *s, hwaddr addr,
> > }
> > break;
> > case SMMU_PTW_ERR_PERMISSION:
> > - if (PTW_RECORD_FAULT(cfg)) {
> > + if (PTW_RECORD_FAULT(ptw_info, cfg)) {
> > event->type = SMMU_EVT_F_PERMISSION;
> > event->u.f_permission.addr = addr;
> > event->u.f_permission.addr2 = ptw_info.addr;
> Thanks
>
> Eric
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 15/18] hw/arm/smmuv3: Advertise S2FWB
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (13 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 14/18] hw/arm/smmuv3: Support and advertise nesting Mostafa Saleh
@ 2024-04-29 3:23 ` Mostafa Saleh
2024-05-20 13:30 ` Eric Auger
2024-04-29 3:24 ` [RFC PATCH v3 16/18] hw/arm/smmu: Refactor SMMU OAS Mostafa Saleh
` (4 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:23 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
QEMU doesn's support memory attributes, so FWB is NOP, this
might change in the future if memory attributre would be supported.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmuv3.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 88f6473d33..8a11e41144 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -287,6 +287,14 @@ static void smmuv3_init_regs(SMMUv3State *s)
if (FIELD_EX32(s->idr[0], IDR0, S2P)) {
/* XNX is a stage-2-specific feature */
s->idr[3] = FIELD_DP32(s->idr[3], IDR3, XNX, 1);
+ if (FIELD_EX32(s->idr[0], IDR0, S1P)) {
+ /*
+ * QEMU doesn's support memory attributes, so FWB is NOP, this
+ * might change in the future if memory attributre would be
+ * supported.
+ */
+ s->idr[3] = FIELD_DP32(s->idr[3], IDR3, FWB, 1);
+ }
}
s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2);
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 15/18] hw/arm/smmuv3: Advertise S2FWB
2024-04-29 3:23 ` [RFC PATCH v3 15/18] hw/arm/smmuv3: Advertise S2FWB Mostafa Saleh
@ 2024-05-20 13:30 ` Eric Auger
2024-06-17 15:04 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-20 13:30 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
On 4/29/24 05:23, Mostafa Saleh wrote:
> QEMU doesn's support memory attributes, so FWB is NOP, this
> might change in the future if memory attributre would be supported.
if mem attributes get supported
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmuv3.c | 8 ++++++++
> 1 file changed, 8 insertions(+)
>
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 88f6473d33..8a11e41144 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -287,6 +287,14 @@ static void smmuv3_init_regs(SMMUv3State *s)
> if (FIELD_EX32(s->idr[0], IDR0, S2P)) {
> /* XNX is a stage-2-specific feature */
> s->idr[3] = FIELD_DP32(s->idr[3], IDR3, XNX, 1);
> + if (FIELD_EX32(s->idr[0], IDR0, S1P)) {
> + /*
> + * QEMU doesn's support memory attributes, so FWB is NOP, this
> + * might change in the future if memory attributre would be
if mem attributes get supported
> + * supported.
> + */
> + s->idr[3] = FIELD_DP32(s->idr[3], IDR3, FWB, 1);
spec says:
0b0 Stage 2 control of memory types and attributes is
not supported and the STE.S2FWB bit is RES 0.
Thanks
Eric
> + }
> }
> s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
> s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2);
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 15/18] hw/arm/smmuv3: Advertise S2FWB
2024-05-20 13:30 ` Eric Auger
@ 2024-06-17 15:04 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-06-17 15:04 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Mon, May 20, 2024 at 03:30:58PM +0200, Eric Auger wrote:
>
>
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > QEMU doesn's support memory attributes, so FWB is NOP, this
> > might change in the future if memory attributre would be supported.
> if mem attributes get supported
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmuv3.c | 8 ++++++++
> > 1 file changed, 8 insertions(+)
> >
> > diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> > index 88f6473d33..8a11e41144 100644
> > --- a/hw/arm/smmuv3.c
> > +++ b/hw/arm/smmuv3.c
> > @@ -287,6 +287,14 @@ static void smmuv3_init_regs(SMMUv3State *s)
> > if (FIELD_EX32(s->idr[0], IDR0, S2P)) {
> > /* XNX is a stage-2-specific feature */
> > s->idr[3] = FIELD_DP32(s->idr[3], IDR3, XNX, 1);
> > + if (FIELD_EX32(s->idr[0], IDR0, S1P)) {
> > + /*
> > + * QEMU doesn's support memory attributes, so FWB is NOP, this
> > + * might change in the future if memory attributre would be
> if mem attributes get supported
> > + * supported.
> > + */
> > + s->idr[3] = FIELD_DP32(s->idr[3], IDR3, FWB, 1);
> spec says:
> 0b0 Stage 2 control of memory types and attributes is
> not supported and the STE.S2FWB bit is RES 0.
My understanding it is still OK for the SMMU to advertise that although as
patch description indicates it is useless, but I thought it is similar to
XNX recently added, but I can drop it if it is not useful.
Thanks,
Mostafa
>
>
> Thanks
>
> Eric
> > + }
> > }
> > s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
> > s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2);
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 16/18] hw/arm/smmu: Refactor SMMU OAS
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (14 preceding siblings ...)
2024-04-29 3:23 ` [RFC PATCH v3 15/18] hw/arm/smmuv3: Advertise S2FWB Mostafa Saleh
@ 2024-04-29 3:24 ` Mostafa Saleh
2024-05-20 13:59 ` Eric Auger
2024-04-29 3:24 ` [RFC PATCH v3 17/18] hw/arm/smmuv3: Add property for OAS Mostafa Saleh
` (3 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:24 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
SMMUv3 OAS is hardcoded to 44 bits, for nested configurations that
can be a problem as stage-2 might be shared with the CPU which might
have different PARANGE, and according to SMMU manual ARM IHI 0070F.b:
6.3.6 SMMU_IDR5, OAS must match the system physical address size.
This patch doesn't change the SMMU OAS, but refactors the code to
make it easier to do that:
- Rely everywhere on IDR5 for reading OAS instead of using the macro so
it is easier just change IDR5 and it propagages correctly.
- Remove unused functions/macros: pa_range/MAX_PA
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmu-common.c | 7 ++++---
hw/arm/smmuv3-internal.h | 13 -------------
hw/arm/smmuv3.c | 35 ++++++++++++++++++++++++++++-------
3 files changed, 32 insertions(+), 23 deletions(-)
diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
index 3ed0be05ef..b559878aef 100644
--- a/hw/arm/smmu-common.c
+++ b/hw/arm/smmu-common.c
@@ -434,7 +434,8 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
inputsize = 64 - tt->tsz;
level = 4 - (inputsize - 4) / stride;
indexmask = VMSA_IDXMSK(inputsize, stride, level);
- baseaddr = extract64(tt->ttb, 0, 48);
+
+ baseaddr = extract64(tt->ttb, 0, cfg->oas);
baseaddr &= ~indexmask;
while (level < VMSA_LEVELS) {
@@ -557,8 +558,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
* Get the ttb from concatenated structure.
* The offset is the idx * size of each ttb(number of ptes * (sizeof(pte))
*/
- uint64_t baseaddr = extract64(cfg->s2cfg.vttb, 0, 48) + (1 << stride) *
- idx * sizeof(uint64_t);
+ uint64_t baseaddr = extract64(cfg->s2cfg.vttb, 0, cfg->s2cfg.eff_ps) +
+ (1 << stride) * idx * sizeof(uint64_t);
dma_addr_t indexmask = VMSA_IDXMSK(inputsize, stride, level);
baseaddr &= ~indexmask;
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index 0f3ecec804..0ebf2eebcf 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -602,19 +602,6 @@ static inline int oas2bits(int oas_field)
return -1;
}
-static inline int pa_range(STE *ste)
-{
- int oas_field = MIN(STE_S2PS(ste), SMMU_IDR5_OAS);
-
- if (!STE_S2AA64(ste)) {
- return 40;
- }
-
- return oas2bits(oas_field);
-}
-
-#define MAX_PA(ste) ((1 << pa_range(ste)) - 1)
-
/* CD fields */
#define CD_VALID(x) extract32((x)->word[0], 31, 1)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 8a11e41144..4ac818cf7a 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -408,10 +408,10 @@ static bool s2t0sz_valid(SMMUTransCfg *cfg)
}
if (cfg->s2cfg.granule_sz == 16) {
- return (cfg->s2cfg.tsz >= 64 - oas2bits(SMMU_IDR5_OAS));
+ return (cfg->s2cfg.tsz >= 64 - cfg->s2cfg.eff_ps);
}
- return (cfg->s2cfg.tsz >= MAX(64 - oas2bits(SMMU_IDR5_OAS), 16));
+ return (cfg->s2cfg.tsz >= MAX(64 - cfg->s2cfg.eff_ps, 16));
}
/*
@@ -432,8 +432,11 @@ static bool s2_pgtable_config_valid(uint8_t sl0, uint8_t t0sz, uint8_t gran)
return nr_concat <= VMSA_MAX_S2_CONCAT;
}
-static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
+static int decode_ste_s2_cfg(SMMUv3State *s, SMMUTransCfg *cfg,
+ STE *ste)
{
+ uint8_t oas = FIELD_EX32(s->idr[5], IDR5, OAS);
+
if (STE_S2AA64(ste) == 0x0) {
qemu_log_mask(LOG_UNIMP,
"SMMUv3 AArch32 tables not supported\n");
@@ -466,7 +469,15 @@ static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
}
/* For AA64, The effective S2PS size is capped to the OAS. */
- cfg->s2cfg.eff_ps = oas2bits(MIN(STE_S2PS(ste), SMMU_IDR5_OAS));
+ cfg->s2cfg.eff_ps = oas2bits(MIN(STE_S2PS(ste), oas));
+ /*
+ * For SMMUv3.1 and later, when OAS == IAS == 52, the stage 2 input
+ * range is further limited to 48 bits unless STE.S2TG indicates a
+ * 64KB granule.
+ */
+ if (cfg->s2cfg.granule_sz != 16) {
+ cfg->s2cfg.eff_ps = MIN(cfg->s2cfg.eff_ps, 48);
+ }
/*
* It is ILLEGAL for the address in S2TTB to be outside the range
* described by the effective S2PS value.
@@ -542,6 +553,7 @@ 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);
int ret;
if (!STE_VALID(ste)) {
@@ -585,8 +597,8 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
* Stage-1 OAS defaults to OAS even if not enabled as it would be used
* in input address check for stage-2.
*/
- cfg->oas = oas2bits(SMMU_IDR5_OAS);
- ret = decode_ste_s2_cfg(cfg, ste);
+ cfg->oas = oas2bits(oas);
+ ret = decode_ste_s2_cfg(s, cfg, ste);
if (ret) {
goto bad_ste;
}
@@ -712,6 +724,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);
if (!CD_VALID(cd) || !CD_AARCH64(cd)) {
goto bad_cd;
@@ -730,7 +743,7 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
cfg->aa64 = true;
cfg->oas = oas2bits(CD_IPS(cd));
- cfg->oas = MIN(oas2bits(SMMU_IDR5_OAS), cfg->oas);
+ cfg->oas = MIN(oas2bits(oas), cfg->oas);
cfg->tbi = CD_TBI(cd);
cfg->asid = CD_ASID(cd);
cfg->affd = CD_AFFD(cd);
@@ -759,6 +772,14 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
goto bad_cd;
}
+ /*
+ * An address greater than 48 bits in size can only be output from a
+ * TTD when, in SMMUv3.1 and later, the effective IPS is 52 and a 64KB
+ * granule is in use for that translation table
+ */
+ if (tt->granule_sz != 16) {
+ cfg->oas = MIN(cfg->oas, 48);
+ }
tt->tsz = tsz;
tt->ttb = CD_TTB(cd, i);
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 16/18] hw/arm/smmu: Refactor SMMU OAS
2024-04-29 3:24 ` [RFC PATCH v3 16/18] hw/arm/smmu: Refactor SMMU OAS Mostafa Saleh
@ 2024-05-20 13:59 ` Eric Auger
0 siblings, 0 replies; 57+ messages in thread
From: Eric Auger @ 2024-05-20 13:59 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:24, Mostafa Saleh wrote:
> SMMUv3 OAS is hardcoded to 44 bits, for nested configurations that
is currently hardcoded in the code.
> can be a problem as stage-2 might be shared with the CPU which might
> have different PARANGE, and according to SMMU manual ARM IHI 0070F.b:
> 6.3.6 SMMU_IDR5, OAS must match the system physical address size.
>
> This patch doesn't change the SMMU OAS, but refactors the code to
> make it easier to do that:
> - Rely everywhere on IDR5 for reading OAS instead of using the macro so
instead of using the SMMU_IDR5_OAS macro.
Also add additional checks when OAS is greater than 48bits
> it is easier just change IDR5 and it propagages correctly.
> - Remove unused functions/macros: pa_range/MAX_PA
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmu-common.c | 7 ++++---
> hw/arm/smmuv3-internal.h | 13 -------------
> hw/arm/smmuv3.c | 35 ++++++++++++++++++++++++++++-------
> 3 files changed, 32 insertions(+), 23 deletions(-)
>
> diff --git a/hw/arm/smmu-common.c b/hw/arm/smmu-common.c
> index 3ed0be05ef..b559878aef 100644
> --- a/hw/arm/smmu-common.c
> +++ b/hw/arm/smmu-common.c
> @@ -434,7 +434,8 @@ static int smmu_ptw_64_s1(SMMUTransCfg *cfg,
> inputsize = 64 - tt->tsz;
> level = 4 - (inputsize - 4) / stride;
> indexmask = VMSA_IDXMSK(inputsize, stride, level);
> - baseaddr = extract64(tt->ttb, 0, 48);
> +
> + baseaddr = extract64(tt->ttb, 0, cfg->oas);
> baseaddr &= ~indexmask;
>
> while (level < VMSA_LEVELS) {
> @@ -557,8 +558,8 @@ static int smmu_ptw_64_s2(SMMUTransCfg *cfg,
> * Get the ttb from concatenated structure.
> * The offset is the idx * size of each ttb(number of ptes * (sizeof(pte))
> */
> - uint64_t baseaddr = extract64(cfg->s2cfg.vttb, 0, 48) + (1 << stride)
> - idx * sizeof(uint64_t);
> + uint64_t baseaddr = extract64(cfg->s2cfg.vttb, 0, cfg->s2cfg.eff_ps) +
> + (1 << stride) * idx * sizeof(uint64_t);
> dma_addr_t indexmask = VMSA_IDXMSK(inputsize, stride, level);
>
> baseaddr &= ~indexmask;
> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> index 0f3ecec804..0ebf2eebcf 100644
> --- a/hw/arm/smmuv3-internal.h
> +++ b/hw/arm/smmuv3-internal.h
> @@ -602,19 +602,6 @@ static inline int oas2bits(int oas_field)
> return -1;
> }
>
> -static inline int pa_range(STE *ste)
> -{
> - int oas_field = MIN(STE_S2PS(ste), SMMU_IDR5_OAS);
> -
> - if (!STE_S2AA64(ste)) {
> - return 40;
> - }
> -
> - return oas2bits(oas_field);
> -}
> -
> -#define MAX_PA(ste) ((1 << pa_range(ste)) - 1)
> -
> /* CD fields */
>
> #define CD_VALID(x) extract32((x)->word[0], 31, 1)
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 8a11e41144..4ac818cf7a 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -408,10 +408,10 @@ static bool s2t0sz_valid(SMMUTransCfg *cfg)
> }
>
> if (cfg->s2cfg.granule_sz == 16) {
> - return (cfg->s2cfg.tsz >= 64 - oas2bits(SMMU_IDR5_OAS));
> + return (cfg->s2cfg.tsz >= 64 - cfg->s2cfg.eff_ps);
> }
>
> - return (cfg->s2cfg.tsz >= MAX(64 - oas2bits(SMMU_IDR5_OAS), 16));
> + return (cfg->s2cfg.tsz >= MAX(64 - cfg->s2cfg.eff_ps, 16));
> }
>
> /*
> @@ -432,8 +432,11 @@ static bool s2_pgtable_config_valid(uint8_t sl0, uint8_t t0sz, uint8_t gran)
> return nr_concat <= VMSA_MAX_S2_CONCAT;
> }
>
> -static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
> +static int decode_ste_s2_cfg(SMMUv3State *s, SMMUTransCfg *cfg,
> + STE *ste)
> {
> + uint8_t oas = FIELD_EX32(s->idr[5], IDR5, OAS);
> +
> if (STE_S2AA64(ste) == 0x0) {
> qemu_log_mask(LOG_UNIMP,
> "SMMUv3 AArch32 tables not supported\n");
> @@ -466,7 +469,15 @@ static int decode_ste_s2_cfg(SMMUTransCfg *cfg, STE *ste)
> }
>
> /* For AA64, The effective S2PS size is capped to the OAS. */
> - cfg->s2cfg.eff_ps = oas2bits(MIN(STE_S2PS(ste), SMMU_IDR5_OAS));
> + cfg->s2cfg.eff_ps = oas2bits(MIN(STE_S2PS(ste), oas));
> + /*
> + * For SMMUv3.1 and later, when OAS == IAS == 52, the stage 2 input
> + * range is further limited to 48 bits unless STE.S2TG indicates a
> + * 64KB granule.
> + */
> + if (cfg->s2cfg.granule_sz != 16) {
> + cfg->s2cfg.eff_ps = MIN(cfg->s2cfg.eff_ps, 48);
> + }
> /*
> * It is ILLEGAL for the address in S2TTB to be outside the range
> * described by the effective S2PS value.
> @@ -542,6 +553,7 @@ 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);
> int ret;
>
> if (!STE_VALID(ste)) {
> @@ -585,8 +597,8 @@ static int decode_ste(SMMUv3State *s, SMMUTransCfg *cfg,
> * Stage-1 OAS defaults to OAS even if not enabled as it would be used
> * in input address check for stage-2.
> */
> - cfg->oas = oas2bits(SMMU_IDR5_OAS);
> - ret = decode_ste_s2_cfg(cfg, ste);
> + cfg->oas = oas2bits(oas);
> + ret = decode_ste_s2_cfg(s, cfg, ste);
> if (ret) {
> goto bad_ste;
> }
> @@ -712,6 +724,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);
>
> if (!CD_VALID(cd) || !CD_AARCH64(cd)) {
> goto bad_cd;
> @@ -730,7 +743,7 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
> cfg->aa64 = true;
>
> cfg->oas = oas2bits(CD_IPS(cd));
> - cfg->oas = MIN(oas2bits(SMMU_IDR5_OAS), cfg->oas);
> + cfg->oas = MIN(oas2bits(oas), cfg->oas);
> cfg->tbi = CD_TBI(cd);
> cfg->asid = CD_ASID(cd);
> cfg->affd = CD_AFFD(cd);
> @@ -759,6 +772,14 @@ static int decode_cd(SMMUv3State *s, SMMUTransCfg *cfg,
> goto bad_cd;
> }
>
> + /*
> + * An address greater than 48 bits in size can only be output from a
> + * TTD when, in SMMUv3.1 and later, the effective IPS is 52 and a 64KB
> + * granule is in use for that translation table
> + */
> + if (tt->granule_sz != 16) {
> + cfg->oas = MIN(cfg->oas, 48);
> + }
> tt->tsz = tsz;
> tt->ttb = CD_TTB(cd, i);
>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Eric
Eric
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 17/18] hw/arm/smmuv3: Add property for OAS
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (15 preceding siblings ...)
2024-04-29 3:24 ` [RFC PATCH v3 16/18] hw/arm/smmu: Refactor SMMU OAS Mostafa Saleh
@ 2024-04-29 3:24 ` Mostafa Saleh
2024-05-21 9:32 ` Eric Auger
2024-04-29 3:24 ` [RFC PATCH v3 18/18] hw/arm/virt: Set SMMU OAS based on CPU PARANGE Mostafa Saleh
` (2 subsequent siblings)
19 siblings, 1 reply; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:24 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
Add property that sets the OAS of the SMMU, this in not used in this
patch.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/smmuv3-internal.h | 3 ++-
hw/arm/smmuv3.c | 29 ++++++++++++++++++++++++++++-
include/hw/arm/smmuv3.h | 1 +
3 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
index 0ebf2eebcf..dd91807624 100644
--- a/hw/arm/smmuv3-internal.h
+++ b/hw/arm/smmuv3-internal.h
@@ -111,7 +111,8 @@ REG32(IDR5, 0x14)
FIELD(IDR5, VAX, 10, 2);
FIELD(IDR5, STALL_MAX, 16, 16);
-#define SMMU_IDR5_OAS 4
+#define SMMU_IDR5_OAS_DEF 4 /* 44 bits. */
+#define SMMU_IDR5_OAS_MAX 5 /* 48 bits. */
REG32(IIDR, 0x18)
REG32(AIDR, 0x1c)
diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
index 4ac818cf7a..39d03e7e24 100644
--- a/hw/arm/smmuv3.c
+++ b/hw/arm/smmuv3.c
@@ -299,7 +299,9 @@ static void smmuv3_init_regs(SMMUv3State *s)
s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2);
- s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */
+ /* PTW doesn't support 52 bits. */
+ s->oas = MIN(s->oas, SMMU_IDR5_OAS_MAX);
+ s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, s->oas);
/* 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);
@@ -1901,11 +1903,34 @@ static const VMStateDescription vmstate_gbpa = {
}
};
+static const VMStateDescription vmstate_oas = {
+ .name = "smmuv3/oas",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .fields = (const VMStateField[]) {
+ VMSTATE_INT32(oas, SMMUv3State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int smmuv3_preload(void *opaque)
+{
+ SMMUv3State *s = opaque;
+
+ /*
+ * In case it wasn't migrated, use the value used
+ * by older QEMU.
+ */
+ s->oas = SMMU_IDR5_OAS_DEF;
+ return 0;
+}
+
static const VMStateDescription vmstate_smmuv3 = {
.name = "smmuv3",
.version_id = 1,
.minimum_version_id = 1,
.priority = MIG_PRI_IOMMU,
+ .pre_load = smmuv3_preload,
.fields = (const VMStateField[]) {
VMSTATE_UINT32(features, SMMUv3State),
VMSTATE_UINT8(sid_size, SMMUv3State),
@@ -1933,6 +1958,7 @@ static const VMStateDescription vmstate_smmuv3 = {
},
.subsections = (const VMStateDescription * const []) {
&vmstate_gbpa,
+ &vmstate_oas,
NULL
}
};
@@ -1945,6 +1971,7 @@ static Property smmuv3_properties[] = {
* Defaults to stage 1
*/
DEFINE_PROP_STRING("stage", SMMUv3State, stage),
+ DEFINE_PROP_INT32("oas", SMMUv3State, oas, SMMU_IDR5_OAS_DEF),
DEFINE_PROP_END_OF_LIST()
};
diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
index d183a62766..00a9eb4467 100644
--- a/include/hw/arm/smmuv3.h
+++ b/include/hw/arm/smmuv3.h
@@ -63,6 +63,7 @@ struct SMMUv3State {
qemu_irq irq[4];
QemuMutex mutex;
char *stage;
+ int32_t oas;
};
typedef enum {
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 17/18] hw/arm/smmuv3: Add property for OAS
2024-04-29 3:24 ` [RFC PATCH v3 17/18] hw/arm/smmuv3: Add property for OAS Mostafa Saleh
@ 2024-05-21 9:32 ` Eric Auger
2024-06-27 11:50 ` Mostafa Saleh
0 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-21 9:32 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:24, Mostafa Saleh wrote:
> Add property that sets the OAS of the SMMU, this in not used in this
> patch.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/smmuv3-internal.h | 3 ++-
> hw/arm/smmuv3.c | 29 ++++++++++++++++++++++++++++-
> include/hw/arm/smmuv3.h | 1 +
> 3 files changed, 31 insertions(+), 2 deletions(-)
>
> diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> index 0ebf2eebcf..dd91807624 100644
> --- a/hw/arm/smmuv3-internal.h
> +++ b/hw/arm/smmuv3-internal.h
> @@ -111,7 +111,8 @@ REG32(IDR5, 0x14)
> FIELD(IDR5, VAX, 10, 2);
> FIELD(IDR5, STALL_MAX, 16, 16);
>
> -#define SMMU_IDR5_OAS 4
> +#define SMMU_IDR5_OAS_DEF 4 /* 44 bits. */
> +#define SMMU_IDR5_OAS_MAX 5 /* 48 bits. */
>
> REG32(IIDR, 0x18)
> REG32(AIDR, 0x1c)
> diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> index 4ac818cf7a..39d03e7e24 100644
> --- a/hw/arm/smmuv3.c
> +++ b/hw/arm/smmuv3.c
> @@ -299,7 +299,9 @@ static void smmuv3_init_regs(SMMUv3State *s)
> s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
> s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2);
>
> - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */
> + /* PTW doesn't support 52 bits. */
remove the point
> + s->oas = MIN(s->oas, SMMU_IDR5_OAS_MAX);
> + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, s->oas);
> /* 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);
> @@ -1901,11 +1903,34 @@ static const VMStateDescription vmstate_gbpa = {
> }
> };
>
> +static const VMStateDescription vmstate_oas = {
> + .name = "smmuv3/oas",
> + .version_id = 1,
> + .minimum_version_id = 1,
don't you need a .needed function?
I tested backward migration and this fails
qemu-system-aarch64: error while loading state for instance 0x0 of
device 'smmuv3'
qemu-system-aarch64: load of migration failed: No such file or directory
post-processing ...
Thanks
Eric
> + .fields = (const VMStateField[]) {
> + VMSTATE_INT32(oas, SMMUv3State),
> + VMSTATE_END_OF_LIST()
> + }
> +};
> +
> +static int smmuv3_preload(void *opaque)
> +{
> + SMMUv3State *s = opaque;
> +
> + /*
> + * In case it wasn't migrated, use the value used
> + * by older QEMU.
> + */
> + s->oas = SMMU_IDR5_OAS_DEF;
> + return 0;
> +}
> +
> static const VMStateDescription vmstate_smmuv3 = {
> .name = "smmuv3",
> .version_id = 1,
> .minimum_version_id = 1,
> .priority = MIG_PRI_IOMMU,
> + .pre_load = smmuv3_preload,
> .fields = (const VMStateField[]) {
> VMSTATE_UINT32(features, SMMUv3State),
> VMSTATE_UINT8(sid_size, SMMUv3State),
> @@ -1933,6 +1958,7 @@ static const VMStateDescription vmstate_smmuv3 = {
> },
> .subsections = (const VMStateDescription * const []) {
> &vmstate_gbpa,
> + &vmstate_oas,
> NULL
> }
> };
> @@ -1945,6 +1971,7 @@ static Property smmuv3_properties[] = {
> * Defaults to stage 1
> */
> DEFINE_PROP_STRING("stage", SMMUv3State, stage),
> + DEFINE_PROP_INT32("oas", SMMUv3State, oas, SMMU_IDR5_OAS_DEF),
> DEFINE_PROP_END_OF_LIST()
> };
>
> diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
> index d183a62766..00a9eb4467 100644
> --- a/include/hw/arm/smmuv3.h
> +++ b/include/hw/arm/smmuv3.h
> @@ -63,6 +63,7 @@ struct SMMUv3State {
> qemu_irq irq[4];
> QemuMutex mutex;
> char *stage;
> + int32_t oas;
> };
>
> typedef enum {
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 17/18] hw/arm/smmuv3: Add property for OAS
2024-05-21 9:32 ` Eric Auger
@ 2024-06-27 11:50 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-06-27 11:50 UTC (permalink / raw)
To: Eric Auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Tue, May 21, 2024 at 11:32:48AM +0200, Eric Auger wrote:
> Hi Mostafa,
>
> On 4/29/24 05:24, Mostafa Saleh wrote:
> > Add property that sets the OAS of the SMMU, this in not used in this
> > patch.
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/smmuv3-internal.h | 3 ++-
> > hw/arm/smmuv3.c | 29 ++++++++++++++++++++++++++++-
> > include/hw/arm/smmuv3.h | 1 +
> > 3 files changed, 31 insertions(+), 2 deletions(-)
> >
> > diff --git a/hw/arm/smmuv3-internal.h b/hw/arm/smmuv3-internal.h
> > index 0ebf2eebcf..dd91807624 100644
> > --- a/hw/arm/smmuv3-internal.h
> > +++ b/hw/arm/smmuv3-internal.h
> > @@ -111,7 +111,8 @@ REG32(IDR5, 0x14)
> > FIELD(IDR5, VAX, 10, 2);
> > FIELD(IDR5, STALL_MAX, 16, 16);
> >
> > -#define SMMU_IDR5_OAS 4
> > +#define SMMU_IDR5_OAS_DEF 4 /* 44 bits. */
> > +#define SMMU_IDR5_OAS_MAX 5 /* 48 bits. */
> >
> > REG32(IIDR, 0x18)
> > REG32(AIDR, 0x1c)
> > diff --git a/hw/arm/smmuv3.c b/hw/arm/smmuv3.c
> > index 4ac818cf7a..39d03e7e24 100644
> > --- a/hw/arm/smmuv3.c
> > +++ b/hw/arm/smmuv3.c
> > @@ -299,7 +299,9 @@ static void smmuv3_init_regs(SMMUv3State *s)
> > s->idr[3] = FIELD_DP32(s->idr[3], IDR3, RIL, 1);
> > s->idr[3] = FIELD_DP32(s->idr[3], IDR3, BBML, 2);
> >
> > - s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, SMMU_IDR5_OAS); /* 44 bits */
> > + /* PTW doesn't support 52 bits. */
> remove the point
> > + s->oas = MIN(s->oas, SMMU_IDR5_OAS_MAX);
> > + s->idr[5] = FIELD_DP32(s->idr[5], IDR5, OAS, s->oas);
> > /* 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);
> > @@ -1901,11 +1903,34 @@ static const VMStateDescription vmstate_gbpa = {
> > }
> > };
> >
> > +static const VMStateDescription vmstate_oas = {
> > + .name = "smmuv3/oas",
> > + .version_id = 1,
> > + .minimum_version_id = 1,
> don't you need a .needed function?
>
> I tested backward migration and this fails
> qemu-system-aarch64: error while loading state for instance 0x0 of
> device 'smmuv3'
> qemu-system-aarch64: load of migration failed: No such file or directory
> post-processing ...
Yes, I think we need a .needed which returns if oas is not as default,
that should be backward compatiable (at least for this patch) and would
break when oas changes.
Thanks,
Mostafa
>
> Thanks
>
> Eric
> > + .fields = (const VMStateField[]) {
> > + VMSTATE_INT32(oas, SMMUv3State),
> > + VMSTATE_END_OF_LIST()
> > + }
> > +};
> > +
> > +static int smmuv3_preload(void *opaque)
> > +{
> > + SMMUv3State *s = opaque;
> > +
> > + /*
> > + * In case it wasn't migrated, use the value used
> > + * by older QEMU.
> > + */
> > + s->oas = SMMU_IDR5_OAS_DEF;
> > + return 0;
> > +}
> > +
> > static const VMStateDescription vmstate_smmuv3 = {
> > .name = "smmuv3",
> > .version_id = 1,
> > .minimum_version_id = 1,
> > .priority = MIG_PRI_IOMMU,
> > + .pre_load = smmuv3_preload,
> > .fields = (const VMStateField[]) {
> > VMSTATE_UINT32(features, SMMUv3State),
> > VMSTATE_UINT8(sid_size, SMMUv3State),
> > @@ -1933,6 +1958,7 @@ static const VMStateDescription vmstate_smmuv3 = {
> > },
> > .subsections = (const VMStateDescription * const []) {
> > &vmstate_gbpa,
> > + &vmstate_oas,
> > NULL
> > }
> > };
> > @@ -1945,6 +1971,7 @@ static Property smmuv3_properties[] = {
> > * Defaults to stage 1
> > */
> > DEFINE_PROP_STRING("stage", SMMUv3State, stage),
> > + DEFINE_PROP_INT32("oas", SMMUv3State, oas, SMMU_IDR5_OAS_DEF),
> > DEFINE_PROP_END_OF_LIST()
> > };
> >
> > diff --git a/include/hw/arm/smmuv3.h b/include/hw/arm/smmuv3.h
> > index d183a62766..00a9eb4467 100644
> > --- a/include/hw/arm/smmuv3.h
> > +++ b/include/hw/arm/smmuv3.h
> > @@ -63,6 +63,7 @@ struct SMMUv3State {
> > qemu_irq irq[4];
> > QemuMutex mutex;
> > char *stage;
> > + int32_t oas;
> > };
> >
> > typedef enum {
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* [RFC PATCH v3 18/18] hw/arm/virt: Set SMMU OAS based on CPU PARANGE
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (16 preceding siblings ...)
2024-04-29 3:24 ` [RFC PATCH v3 17/18] hw/arm/smmuv3: Add property for OAS Mostafa Saleh
@ 2024-04-29 3:24 ` Mostafa Saleh
2024-05-21 9:43 ` Eric Auger
2024-05-24 17:22 ` Julien Grall
2024-05-13 13:57 ` [RFC PATCH v3 00/18] SMMUv3 nested translation support Julien Grall
2024-05-21 9:47 ` Eric Auger
19 siblings, 2 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-04-29 3:24 UTC (permalink / raw)
To: qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz, Mostafa Saleh
Use the new SMMU property to make the SMMU OAS match the CPU PARANGE.
That's according to SMMU manual ARM IHI 0070F.b:
6.3.6 SMMU_IDR5, OAS must match the system physical address size.
Signed-off-by: Mostafa Saleh <smostafa@google.com>
---
hw/arm/virt.c | 14 ++++++++++++--
target/arm/cpu.h | 2 ++
target/arm/cpu64.c | 5 +++++
3 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 3c93c0c0a6..f203b1f8e1 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -252,6 +252,13 @@ static bool ns_el2_virt_timer_present(void)
arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu);
}
+/* We rely on CPU to define system OAS. */
+static int32_t get_system_oas(void)
+{
+ ARMCPU *cpu = ARM_CPU(qemu_get_cpu(0));
+ return cpu_arm_get_oas(cpu);
+}
+
static void create_fdt(VirtMachineState *vms)
{
MachineState *ms = MACHINE(vms);
@@ -1384,7 +1391,7 @@ static void create_pcie_irq_map(const MachineState *ms,
}
static void create_smmu(const VirtMachineState *vms,
- PCIBus *bus)
+ PCIBus *bus, int32_t oas)
{
char *node;
const char compat[] = "arm,smmu-v3";
@@ -1404,6 +1411,9 @@ static void create_smmu(const VirtMachineState *vms,
object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus),
&error_abort);
+
+ qdev_prop_set_uint64(dev, "oas", oas);
+
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
for (i = 0; i < NUM_SMMU_IRQS; i++) {
@@ -1578,7 +1588,7 @@ static void create_pcie(VirtMachineState *vms)
switch (vms->iommu) {
case VIRT_IOMMU_SMMUV3:
- create_smmu(vms, vms->bus);
+ create_smmu(vms, vms->bus, get_system_oas());
qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map",
0x0, vms->iommu_phandle, 0x0, 0x10000);
break;
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index 17efc5d565..68261ffbf9 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3287,4 +3287,6 @@ static inline target_ulong cpu_untagged_addr(CPUState *cs, target_ulong x)
}
#endif
+int32_t cpu_arm_get_oas(ARMCPU *cpu);
+
#endif
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 985b1efe16..08da83c082 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -787,6 +787,11 @@ static const gchar *aarch64_gdb_arch_name(CPUState *cs)
return "aarch64";
}
+int32_t cpu_arm_get_oas(ARMCPU *cpu)
+{
+ return FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE);
+}
+
static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
{
CPUClass *cc = CPU_CLASS(oc);
--
2.44.0.769.g3c40516874-goog
^ permalink raw reply related [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 18/18] hw/arm/virt: Set SMMU OAS based on CPU PARANGE
2024-04-29 3:24 ` [RFC PATCH v3 18/18] hw/arm/virt: Set SMMU OAS based on CPU PARANGE Mostafa Saleh
@ 2024-05-21 9:43 ` Eric Auger
2024-05-24 17:22 ` Julien Grall
1 sibling, 0 replies; 57+ messages in thread
From: Eric Auger @ 2024-05-21 9:43 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:24, Mostafa Saleh wrote:
> Use the new SMMU property to make the SMMU OAS match the CPU PARANGE.
> That's according to SMMU manual ARM IHI 0070F.b:
> 6.3.6 SMMU_IDR5, OAS must match the system physical address size.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/virt.c | 14 ++++++++++++--
> target/arm/cpu.h | 2 ++
> target/arm/cpu64.c | 5 +++++
> 3 files changed, 19 insertions(+), 2 deletions(-)
>
> diff --git a/hw/arm/virt.c b/hw/arm/virt.c
> index 3c93c0c0a6..f203b1f8e1 100644
> --- a/hw/arm/virt.c
> +++ b/hw/arm/virt.c
> @@ -252,6 +252,13 @@ static bool ns_el2_virt_timer_present(void)
> arm_feature(env, ARM_FEATURE_EL2) && cpu_isar_feature(aa64_vh, cpu);
> }
>
> +/* We rely on CPU to define system OAS. */
> +static int32_t get_system_oas(void)
> +{
> + ARMCPU *cpu = ARM_CPU(qemu_get_cpu(0));
> + return cpu_arm_get_oas(cpu);
> +}
> +
> static void create_fdt(VirtMachineState *vms)
> {
> MachineState *ms = MACHINE(vms);
> @@ -1384,7 +1391,7 @@ static void create_pcie_irq_map(const MachineState *ms,
> }
>
> static void create_smmu(const VirtMachineState *vms,
> - PCIBus *bus)
> + PCIBus *bus, int32_t oas)
> {
> char *node;
> const char compat[] = "arm,smmu-v3";
> @@ -1404,6 +1411,9 @@ static void create_smmu(const VirtMachineState *vms,
>
> object_property_set_link(OBJECT(dev), "primary-bus", OBJECT(bus),
> &error_abort);
> +
> + qdev_prop_set_uint64(dev, "oas", oas);
to me you cannot handle that this way because for older machine types
the smmu oas needs to stay the same as it was before, ie. 44. So you
need to properly handle the compats.
Since the new default value depends on the CPU PARANGE this is a bit
more tricky but maybe you get can inspired from no_its class field trick
in virt.c and introduce a no_smmu_cpu_oas_align to disable the settings
up to 9.0 included.
Thanks
Eric
> +
> sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, base);
> for (i = 0; i < NUM_SMMU_IRQS; i++) {
> @@ -1578,7 +1588,7 @@ static void create_pcie(VirtMachineState *vms)
>
> switch (vms->iommu) {
> case VIRT_IOMMU_SMMUV3:
> - create_smmu(vms, vms->bus);
> + create_smmu(vms, vms->bus, get_system_oas());
> qemu_fdt_setprop_cells(ms->fdt, nodename, "iommu-map",
> 0x0, vms->iommu_phandle, 0x0, 0x10000);
> break;
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index 17efc5d565..68261ffbf9 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -3287,4 +3287,6 @@ static inline target_ulong cpu_untagged_addr(CPUState *cs, target_ulong x)
> }
> #endif
>
> +int32_t cpu_arm_get_oas(ARMCPU *cpu);
> +
> #endif
> diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
> index 985b1efe16..08da83c082 100644
> --- a/target/arm/cpu64.c
> +++ b/target/arm/cpu64.c
> @@ -787,6 +787,11 @@ static const gchar *aarch64_gdb_arch_name(CPUState *cs)
> return "aarch64";
> }
>
> +int32_t cpu_arm_get_oas(ARMCPU *cpu)
> +{
> + return FIELD_EX64(cpu->isar.id_aa64mmfr0, ID_AA64MMFR0, PARANGE);
> +}
> +
> static void aarch64_cpu_class_init(ObjectClass *oc, void *data)
> {
> CPUClass *cc = CPU_CLASS(oc);
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 18/18] hw/arm/virt: Set SMMU OAS based on CPU PARANGE
2024-04-29 3:24 ` [RFC PATCH v3 18/18] hw/arm/virt: Set SMMU OAS based on CPU PARANGE Mostafa Saleh
2024-05-21 9:43 ` Eric Auger
@ 2024-05-24 17:22 ` Julien Grall
2024-06-27 11:44 ` Mostafa Saleh
1 sibling, 1 reply; 57+ messages in thread
From: Julien Grall @ 2024-05-24 17:22 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, richard.henderson,
marcin.juszkiewicz
Hi Mostafa,
On 29/04/2024 04:24, Mostafa Saleh wrote:
> Use the new SMMU property to make the SMMU OAS match the CPU PARANGE.
> That's according to SMMU manual ARM IHI 0070F.b: > 6.3.6 SMMU_IDR5, OAS must match the system physical address size.
>
> Signed-off-by: Mostafa Saleh <smostafa@google.com>
> ---
> hw/arm/virt.c | 14 ++++++++++++--
> target/arm/cpu.h | 2 ++
> target/arm/cpu64.c | 5 +++++
When trying to build qemu-system-arm, I get the following error:
[1/3028] Generating subprojects/dtc/version_gen.h with a custom command
[2/3028] Generating qemu-version.h with a custom command (wrapped by
meson to capture output)
[3/3021] Linking target qemu-system-aarch64
[4/3021] Linking target qemu-system-arm
FAILED: qemu-system-arm
clang -m64 -mcx16 @qemu-system-arm.rsp
libqemu-arm-softmmu.fa.p/hw_arm_virt.c.o: In function `get_system_oas':
/home/jgrall/works/oss/qemu/build/../hw/arm/virt.c:259: undefined
reference to `cpu_arm_get_oas'
clang-11: error: linker command failed with exit code 1 (use -v to see
invocation)
ninja: build stopped: subcommand failed.
make: *** [run-ninja] Error 1
I think you need to provide cpu_arm_get_oas() also for 32-bit arm (I
guess it is implemented in target/arm/cpu.c).
Cheers,
--
Julien Grall
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 18/18] hw/arm/virt: Set SMMU OAS based on CPU PARANGE
2024-05-24 17:22 ` Julien Grall
@ 2024-06-27 11:44 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-06-27 11:44 UTC (permalink / raw)
To: Julien Grall
Cc: qemu-arm, eric.auger, peter.maydell, qemu-devel, jean-philippe,
alex.bennee, maz, nicolinc, richard.henderson, marcin.juszkiewicz
Hi Julien,
On Fri, May 24, 2024 at 06:22:12PM +0100, Julien Grall wrote:
> Hi Mostafa,
>
> On 29/04/2024 04:24, Mostafa Saleh wrote:
> > Use the new SMMU property to make the SMMU OAS match the CPU PARANGE.
> > That's according to SMMU manual ARM IHI 0070F.b: > 6.3.6 SMMU_IDR5, OAS must match the system physical address size.
>
> >
> > Signed-off-by: Mostafa Saleh <smostafa@google.com>
> > ---
> > hw/arm/virt.c | 14 ++++++++++++--
> > target/arm/cpu.h | 2 ++
> > target/arm/cpu64.c | 5 +++++
>
> When trying to build qemu-system-arm, I get the following error:
>
> [1/3028] Generating subprojects/dtc/version_gen.h with a custom command
> [2/3028] Generating qemu-version.h with a custom command (wrapped by meson
> to capture output)
> [3/3021] Linking target qemu-system-aarch64
> [4/3021] Linking target qemu-system-arm
> FAILED: qemu-system-arm
> clang -m64 -mcx16 @qemu-system-arm.rsp
> libqemu-arm-softmmu.fa.p/hw_arm_virt.c.o: In function `get_system_oas':
> /home/jgrall/works/oss/qemu/build/../hw/arm/virt.c:259: undefined reference
> to `cpu_arm_get_oas'
> clang-11: error: linker command failed with exit code 1 (use -v to see
> invocation)
> ninja: build stopped: subcommand failed.
> make: *** [run-ninja] Error 1
>
> I think you need to provide cpu_arm_get_oas() also for 32-bit arm (I guess
> it is implemented in target/arm/cpu.c).
>
Ouch, thanks for testing that, I am currently reworking this and migh drop
this change as Eric suggested, but I will make sure it also builds for arm.
Thanks,
Mostafa
> Cheers,
>
> --
> Julien Grall
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 00/18] SMMUv3 nested translation support
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (17 preceding siblings ...)
2024-04-29 3:24 ` [RFC PATCH v3 18/18] hw/arm/virt: Set SMMU OAS based on CPU PARANGE Mostafa Saleh
@ 2024-05-13 13:57 ` Julien Grall
2024-05-21 9:47 ` Eric Auger
19 siblings, 0 replies; 57+ messages in thread
From: Julien Grall @ 2024-05-13 13:57 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, eric.auger, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, richard.henderson,
marcin.juszkiewicz
Hi Mostafa,
On 29/04/2024 04:23, Mostafa Saleh wrote:
> Future improvements:
> =====================
> 1) One small improvement, that I don’t think it’s worth the extra
> complexity, is in case of Stage-1 TLB miss for nested translation,
> we can do stage-1 walk and lookup for stage-2 TLBs, instead of
> doing the full walk.
>
> Testing
> ========
> 1) IOMMUFD + VFIO
> Kernel: https://lore.kernel.org/all/cover.1683688960.git.nicolinc@nvidia.com/
> VMM: https://qemu-devel.nongnu.narkive.com/o815DqpI/rfc-v5-0-8-arm-smmuv3-emulation-support
>
> By assigning “virtio-net-pci,netdev=net0,disable-legacy=on,iommu_platform=on,ats=on”,
> to a guest VM (on top of QEMU guest) with VIFO and IOMMUFD.
>
> 2) Work in progress prototype I am hacking on for nesting on KVM
> (this is nowhere near complete, and misses many stuff but it
> doesn't require VMs/VFIO) also with virtio-net-pci and git
> cloning a bunch of stuff and also observing traces.
> https://android-kvm.googlesource.com/linux/+log/refs/heads/smostafa/android15-6.6-smmu-nesting-wip
>
> I also modified the Linux driver to test with mixed granules/levels.
We have tested the series as well:
Tested-by: Julien Grall <jgrall@amazon.co.uk>
Cheers,
--
Julien Grall
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 00/18] SMMUv3 nested translation support
2024-04-29 3:23 [RFC PATCH v3 00/18] SMMUv3 nested translation support Mostafa Saleh
` (18 preceding siblings ...)
2024-05-13 13:57 ` [RFC PATCH v3 00/18] SMMUv3 nested translation support Julien Grall
@ 2024-05-21 9:47 ` Eric Auger
2024-05-27 16:12 ` Mostafa Saleh
19 siblings, 1 reply; 57+ messages in thread
From: Eric Auger @ 2024-05-21 9:47 UTC (permalink / raw)
To: Mostafa Saleh, qemu-arm, peter.maydell, qemu-devel
Cc: jean-philippe, alex.bennee, maz, nicolinc, julien,
richard.henderson, marcin.juszkiewicz
Hi Mostafa,
On 4/29/24 05:23, Mostafa Saleh wrote:
> Currently, QEMU supports emulating either stage-1 or stage-2 SMMUs
> but not nested instances.
> This patch series adds support for nested translation in SMMUv3,
> this is controlled by property “arm-smmuv3.stage=nested”, and
> advertised to guests as (IDR0.S1P == 1 && IDR0.S2P == 2)
>
> Main changes(architecture):
> ============================
> 1) CDs are considered IPA and translated with stage-2.
> 2) TTBx and tables for stage-1 are considered IPA and translated
> with stage-2.
> 3) Translate the IPA address with stage-2.
>
> TLBs:
> ======
> TLBs are the most tricky part.
>
> 1) General design
> Unified(Combined) design is used, where entries with ASID=-1 are
> IPAs(cached from stage-2 config)
>
> TLBs are also modified to cache 2 permissions, a new permission added
> "parent_perm."
>
> For non-nested configuration, perm == parent_perm and nothing
> changes. This is used to know which stage to use in case there is
> a permission fault from a TLB entry.
>
> 2) Caching in TLB
> Stage-1 and stage-2 are inserted in the TLB as is.
> For nested translation, both entries are combined into one TLB
> entry. The size (level and granule) are chosen from the smallest entries.
> That means that a stage-1 translation can be cached with sage-2
> granule in key, this is take into account lookup.
>
> 3) TLB Lookup
> TLB lookup already uses ASID in key, so it can distinguish between
> stage-1 and stage-2.
> And as mentioned above, the granule for stage-1 can be different,
> If stage-1 lookup failed, we try again with the stage-2 granule.
>
> 4) TLB invalidation
> - Address invalidation is split, for IOVA(CMD_TLBI_NH_VA
> /CMD_TLBI_NH_VAA) and IPA(CMD_TLBI_S2_IPA) based on ASID value
> - CMD_TLBI_NH_ASID/CMD_TLBI_NH_ALL: Consider VMID if stage-2 is
> supported, and invalidate stage-1 only by VMIDs
>
> As far as I understand, this is compliant with the ARM architecture:
> - ARM ARM DDI 0487J.a: RLGSCG, RTVTYQ, RGNJPZ
> - ARM IHI 0070F.b: 16.2 Caching
>
> An alternative approach would be to instantiate 2 TLBs, one per each
> stage. I haven’t investigated that.
>
> Others
> =======
> - Advertise SMMUv3.2-S2FWB, it is NOP for QEMU as it doesn’t support
> attributes.
>
> - OAS: A typical setup with nesting is to share CPU stage-2 with the
> SMMU, and according to the user manual, SMMU OAS must match the
> system physical address.
>
> This was discussed before in
> https://lore.kernel.org/all/20230226220650.1480786-11-smostafa@google.com/
> The implementation here, follows the discussion, where migration is
> added and oas is set up from the board (virt). However, the OAS is
> chosen based on the CPU PARANGE as there is no fixed one.
>
> - For nested configuration, IOVA notifier only notifies for stage-1
> invalidations (as far as I understand this is the intended
> behaviour as it notifies for IOVA)
>
> - Stop ignoring VMID for stage-1 if stage-2 is also supported.
I completed the review pass on my end. I strongly encourage you to move
the series into a non RFC series to attract more reviewers. Migration
needs to be fixed and compat handling as well I think but overall the
nested support looks mostly OK for me. Some stuff are a bit hacky (like
config local patching to force S2 only) as I mentionned in my comments
but let see if other reviewers find some more elegant ways to handle things
Eric
>
>
> Future improvements:
> =====================
> 1) One small improvement, that I don’t think it’s worth the extra
> complexity, is in case of Stage-1 TLB miss for nested translation,
> we can do stage-1 walk and lookup for stage-2 TLBs, instead of
> doing the full walk.
>
> Testing
> ========
> 1) IOMMUFD + VFIO
> Kernel: https://lore.kernel.org/all/cover.1683688960.git.nicolinc@nvidia.com/
> VMM: https://qemu-devel.nongnu.narkive.com/o815DqpI/rfc-v5-0-8-arm-smmuv3-emulation-support
>
> By assigning “virtio-net-pci,netdev=net0,disable-legacy=on,iommu_platform=on,ats=on”,
> to a guest VM (on top of QEMU guest) with VIFO and IOMMUFD.
>
> 2) Work in progress prototype I am hacking on for nesting on KVM
> (this is nowhere near complete, and misses many stuff but it
> doesn't require VMs/VFIO) also with virtio-net-pci and git
> cloning a bunch of stuff and also observing traces.
> https://android-kvm.googlesource.com/linux/+log/refs/heads/smostafa/android15-6.6-smmu-nesting-wip
>
> I also modified the Linux driver to test with mixed granules/levels.
>
> hw/arm/smmuv3: Split smmuv3_translate() better viewed with --color-moved
>
> The first 3 patches are fixes.
>
> Changes in v3
> v2: https://lore.kernel.org/qemu-devel/20240408140818.3799590-1-smostafa@google.com/
> - Collected Eric Rbs.
> - Rebased on master.
> - Fix an existing bug in class encoding.
> - Fix an existing bug in S2 events missing IPA.
> - Fix nesting event population (missing class and wrong events)
> - Remove CALL_FUNC_CFG_S2.
> - Rework TLB combination logic to cache the largest possible entries.
> - Refactor nested translation code to be more clear.
> - Split patch 05 to 4 patches.
> - Convert asid/vmid in trace events to int also.
> - Remove some extra traces as it was not needed.
> - Improve commit messages.
>
> Changes in v2:
> v1: https://lore.kernel.org/qemu-devel/20240325101442.1306300-1-smostafa@google.com/
> - Collected Eric Rbs
> - Rework TLB to rely on VMID/ASID instead of an extra key.
> - Fixed TLB issue with large stage-1 reported by Julian.
> - Cap the OAS to 48 bits as PTW doesn’t support 52 bits.
> - Fix ASID/VMID representation in some contexts as 16 bits while
> they can be -1
> - Increase visibility in trace points
>
> Mostafa Saleh (18):
> hw/arm/smmu-common: Add missing size check for stage-1
> hw/arm/smmu: Fix IPA for stage-2 events
> hw/arm/smmuv3: Fix encoding of CLASS in events
> hw/arm/smmu: Use enum for SMMU stage
> hw/arm/smmu: Split smmuv3_translate()
> hw/arm/smmu: Consolidate ASID and VMID types
> hw/arm/smmuv3: Translate CD and TT using stage-2 table
> hw/arm/smmu-common: Add support for nested TLB
> hw/arm/smmu-common: Rework TLB lookup for nesting
> hw/arm/smmu-common: Support nested translation
> hw/arm/smmu: Support nesting in smmuv3_range_inval()
> hw/arm/smmu: Support nesting in the rest of commands
> hw/arm/smmuv3: Support nested SMMUs in smmuv3_notify_iova()
> hw/arm/smmuv3: Support and advertise nesting
> hw/arm/smmuv3: Advertise S2FWB
> hw/arm/smmu: Refactor SMMU OAS
> hw/arm/smmuv3: Add property for OAS
> hw/arm/virt: Set SMMU OAS based on CPU PARANGE
>
> hw/arm/smmu-common.c | 298 ++++++++++++++++++++---
> hw/arm/smmuv3-internal.h | 22 +-
> hw/arm/smmuv3.c | 441 +++++++++++++++++++++++------------
> hw/arm/trace-events | 26 ++-
> hw/arm/virt.c | 14 +-
> include/hw/arm/smmu-common.h | 43 +++-
> include/hw/arm/smmuv3.h | 1 +
> target/arm/cpu.h | 2 +
> target/arm/cpu64.c | 5 +
> 9 files changed, 625 insertions(+), 227 deletions(-)
>
^ permalink raw reply [flat|nested] 57+ messages in thread
* Re: [RFC PATCH v3 00/18] SMMUv3 nested translation support
2024-05-21 9:47 ` Eric Auger
@ 2024-05-27 16:12 ` Mostafa Saleh
0 siblings, 0 replies; 57+ messages in thread
From: Mostafa Saleh @ 2024-05-27 16:12 UTC (permalink / raw)
To: eric.auger
Cc: qemu-arm, peter.maydell, qemu-devel, jean-philippe, alex.bennee,
maz, nicolinc, julien, richard.henderson, marcin.juszkiewicz
Hi Eric,
On Tue, May 21, 2024 at 10:47 AM Eric Auger <eric.auger@redhat.com> wrote:
>
> Hi Mostafa,
>
> On 4/29/24 05:23, Mostafa Saleh wrote:
> > Currently, QEMU supports emulating either stage-1 or stage-2 SMMUs
> > but not nested instances.
> > This patch series adds support for nested translation in SMMUv3,
> > this is controlled by property “arm-smmuv3.stage=nested”, and
> > advertised to guests as (IDR0.S1P == 1 && IDR0.S2P == 2)
> >
> > Main changes(architecture):
> > ============================
> > 1) CDs are considered IPA and translated with stage-2.
> > 2) TTBx and tables for stage-1 are considered IPA and translated
> > with stage-2.
> > 3) Translate the IPA address with stage-2.
> >
> > TLBs:
> > ======
> > TLBs are the most tricky part.
> >
> > 1) General design
> > Unified(Combined) design is used, where entries with ASID=-1 are
> > IPAs(cached from stage-2 config)
> >
> > TLBs are also modified to cache 2 permissions, a new permission added
> > "parent_perm."
> >
> > For non-nested configuration, perm == parent_perm and nothing
> > changes. This is used to know which stage to use in case there is
> > a permission fault from a TLB entry.
> >
> > 2) Caching in TLB
> > Stage-1 and stage-2 are inserted in the TLB as is.
> > For nested translation, both entries are combined into one TLB
> > entry. The size (level and granule) are chosen from the smallest entries.
> > That means that a stage-1 translation can be cached with sage-2
> > granule in key, this is take into account lookup.
> >
> > 3) TLB Lookup
> > TLB lookup already uses ASID in key, so it can distinguish between
> > stage-1 and stage-2.
> > And as mentioned above, the granule for stage-1 can be different,
> > If stage-1 lookup failed, we try again with the stage-2 granule.
> >
> > 4) TLB invalidation
> > - Address invalidation is split, for IOVA(CMD_TLBI_NH_VA
> > /CMD_TLBI_NH_VAA) and IPA(CMD_TLBI_S2_IPA) based on ASID value
> > - CMD_TLBI_NH_ASID/CMD_TLBI_NH_ALL: Consider VMID if stage-2 is
> > supported, and invalidate stage-1 only by VMIDs
> >
> > As far as I understand, this is compliant with the ARM architecture:
> > - ARM ARM DDI 0487J.a: RLGSCG, RTVTYQ, RGNJPZ
> > - ARM IHI 0070F.b: 16.2 Caching
> >
> > An alternative approach would be to instantiate 2 TLBs, one per each
> > stage. I haven’t investigated that.
> >
> > Others
> > =======
> > - Advertise SMMUv3.2-S2FWB, it is NOP for QEMU as it doesn’t support
> > attributes.
> >
> > - OAS: A typical setup with nesting is to share CPU stage-2 with the
> > SMMU, and according to the user manual, SMMU OAS must match the
> > system physical address.
> >
> > This was discussed before in
> > https://lore.kernel.org/all/20230226220650.1480786-11-smostafa@google.com/
> > The implementation here, follows the discussion, where migration is
> > added and oas is set up from the board (virt). However, the OAS is
> > chosen based on the CPU PARANGE as there is no fixed one.
> >
> > - For nested configuration, IOVA notifier only notifies for stage-1
> > invalidations (as far as I understand this is the intended
> > behaviour as it notifies for IOVA)
> >
> > - Stop ignoring VMID for stage-1 if stage-2 is also supported.
>
> I completed the review pass on my end. I strongly encourage you to move
> the series into a non RFC series to attract more reviewers. Migration
> needs to be fixed and compat handling as well I think but overall the
> nested support looks mostly OK for me. Some stuff are a bit hacky (like
> config local patching to force S2 only) as I mentionned in my comments
> but let see if other reviewers find some more elegant ways to handle things
>
Thanks a lot, I really appreciate your thorough review.
I will send a v4 without RFC in ~2 weeks as I am off for a while.
I will probably drop the OAS changes (again) to avoid the migration
hassle and this can be a separate series after this one,
Thanks,
Mostafa
> Eric
> >
> >
> > Future improvements:
> > =====================
> > 1) One small improvement, that I don’t think it’s worth the extra
> > complexity, is in case of Stage-1 TLB miss for nested translation,
> > we can do stage-1 walk and lookup for stage-2 TLBs, instead of
> > doing the full walk.
> >
> > Testing
> > ========
> > 1) IOMMUFD + VFIO
> > Kernel: https://lore.kernel.org/all/cover.1683688960.git.nicolinc@nvidia.com/
> > VMM: https://qemu-devel.nongnu.narkive.com/o815DqpI/rfc-v5-0-8-arm-smmuv3-emulation-support
> >
> > By assigning “virtio-net-pci,netdev=net0,disable-legacy=on,iommu_platform=on,ats=on”,
> > to a guest VM (on top of QEMU guest) with VIFO and IOMMUFD.
> >
> > 2) Work in progress prototype I am hacking on for nesting on KVM
> > (this is nowhere near complete, and misses many stuff but it
> > doesn't require VMs/VFIO) also with virtio-net-pci and git
> > cloning a bunch of stuff and also observing traces.
> > https://android-kvm.googlesource.com/linux/+log/refs/heads/smostafa/android15-6.6-smmu-nesting-wip
> >
> > I also modified the Linux driver to test with mixed granules/levels.
> >
> > hw/arm/smmuv3: Split smmuv3_translate() better viewed with --color-moved
> >
> > The first 3 patches are fixes.
> >
> > Changes in v3
> > v2: https://lore.kernel.org/qemu-devel/20240408140818.3799590-1-smostafa@google.com/
> > - Collected Eric Rbs.
> > - Rebased on master.
> > - Fix an existing bug in class encoding.
> > - Fix an existing bug in S2 events missing IPA.
> > - Fix nesting event population (missing class and wrong events)
> > - Remove CALL_FUNC_CFG_S2.
> > - Rework TLB combination logic to cache the largest possible entries.
> > - Refactor nested translation code to be more clear.
> > - Split patch 05 to 4 patches.
> > - Convert asid/vmid in trace events to int also.
> > - Remove some extra traces as it was not needed.
> > - Improve commit messages.
> >
> > Changes in v2:
> > v1: https://lore.kernel.org/qemu-devel/20240325101442.1306300-1-smostafa@google.com/
> > - Collected Eric Rbs
> > - Rework TLB to rely on VMID/ASID instead of an extra key.
> > - Fixed TLB issue with large stage-1 reported by Julian.
> > - Cap the OAS to 48 bits as PTW doesn’t support 52 bits.
> > - Fix ASID/VMID representation in some contexts as 16 bits while
> > they can be -1
> > - Increase visibility in trace points
> >
> > Mostafa Saleh (18):
> > hw/arm/smmu-common: Add missing size check for stage-1
> > hw/arm/smmu: Fix IPA for stage-2 events
> > hw/arm/smmuv3: Fix encoding of CLASS in events
> > hw/arm/smmu: Use enum for SMMU stage
> > hw/arm/smmu: Split smmuv3_translate()
> > hw/arm/smmu: Consolidate ASID and VMID types
> > hw/arm/smmuv3: Translate CD and TT using stage-2 table
> > hw/arm/smmu-common: Add support for nested TLB
> > hw/arm/smmu-common: Rework TLB lookup for nesting
> > hw/arm/smmu-common: Support nested translation
> > hw/arm/smmu: Support nesting in smmuv3_range_inval()
> > hw/arm/smmu: Support nesting in the rest of commands
> > hw/arm/smmuv3: Support nested SMMUs in smmuv3_notify_iova()
> > hw/arm/smmuv3: Support and advertise nesting
> > hw/arm/smmuv3: Advertise S2FWB
> > hw/arm/smmu: Refactor SMMU OAS
> > hw/arm/smmuv3: Add property for OAS
> > hw/arm/virt: Set SMMU OAS based on CPU PARANGE
> >
> > hw/arm/smmu-common.c | 298 ++++++++++++++++++++---
> > hw/arm/smmuv3-internal.h | 22 +-
> > hw/arm/smmuv3.c | 441 +++++++++++++++++++++++------------
> > hw/arm/trace-events | 26 ++-
> > hw/arm/virt.c | 14 +-
> > include/hw/arm/smmu-common.h | 43 +++-
> > include/hw/arm/smmuv3.h | 1 +
> > target/arm/cpu.h | 2 +
> > target/arm/cpu64.c | 5 +
> > 9 files changed, 625 insertions(+), 227 deletions(-)
> >
>
^ permalink raw reply [flat|nested] 57+ messages in thread