* [PATCH v4 0/2] iommu: Avoid setting C-bit for MMIO addresses
@ 2025-12-16 16:13 Wei Wang
2025-12-16 16:13 ` [PATCH v4 1/2] iommupt: Do not set C-bit on MMIO backed PTEs Wei Wang
2025-12-16 16:13 ` [PATCH v4 2/2] vfio/type1: Set IOMMU_MMIO in dma->prot for MMIO-backed addresses Wei Wang
0 siblings, 2 replies; 6+ messages in thread
From: Wei Wang @ 2025-12-16 16:13 UTC (permalink / raw)
To: jgg, kevin.tian, alex, joro, thomas.lendacky, vasant.hegde,
suravee.suthikulpanit, aik
Cc: iommu, linux-kernel, wei.w.wang
AMD APM specifies that any pages corresponding to MMIO addresses must be
configured with the C-bit clear. The current iommu implementation sets
the C-bit on all PTEs in the IOMMU page tables. This is incorrect for PTEs
backed by MMIO, and can break PCIe peer-to-peer communication when IOVA is
used. Fix this by avoiding the C-bit for MMIO-backed mappings.
v3->v4 change:
- In the 2nd patch, moved the VM_IO check into the
if (is_invalid_reserved_pfn(*pfn)) {} code block to avoid checking it on
error paths.
v3 link: https://lore.kernel.org/lkml/SI2PR01MB439337D5513729BAC122F526DCCDA@SI2PR01MB4393.apcprd01.prod.exchangelabs.com/
v2->v3 changes:
- re-implement the iommu part based on the iommu tree which has the
iommupt patches merged.
v2 link: https://lore.kernel.org/lkml/SI2PR01MB439373CA7A023D8EC4C42040DCC7A@SI2PR01MB4393.apcprd01.prod.exchangelabs.com/
v1->v2 changes:
- 1 used page_is_ram() in the AMD IOMMU driver to detect non-RAM
addresses, avoiding changes to upper-layer callers (vfio and iommufd).
v2 instead lets upper layers explicitly indicate MMIO mappings via the
IOMMU_MMIO prot flag. This avoids the potential overhead of
page_is_ram(). (suggested by Jason Gunthorpe)
v1 link: https://lore.kernel.org/lkml/SI2PR01MB439358422CCAABADBEB21D7CDCF0A@SI2PR01MB4393.apcprd01.prod.exchangelabs.com/
Wei Wang (2):
iommupt: Do not set C-bit on MMIO backed PTEs
vfio/type1: Set IOMMU_MMIO in dma->prot for MMIO-backed addresses
drivers/iommu/generic_pt/fmt/amdv1.h | 3 ++-
drivers/iommu/generic_pt/fmt/x86_64.h | 3 ++-
drivers/vfio/vfio_iommu_type1.c | 14 +++++++++-----
3 files changed, 13 insertions(+), 7 deletions(-)
--
2.51.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v4 1/2] iommupt: Do not set C-bit on MMIO backed PTEs
2025-12-16 16:13 [PATCH v4 0/2] iommu: Avoid setting C-bit for MMIO addresses Wei Wang
@ 2025-12-16 16:13 ` Wei Wang
2025-12-16 16:13 ` [PATCH v4 2/2] vfio/type1: Set IOMMU_MMIO in dma->prot for MMIO-backed addresses Wei Wang
1 sibling, 0 replies; 6+ messages in thread
From: Wei Wang @ 2025-12-16 16:13 UTC (permalink / raw)
To: jgg, kevin.tian, alex, joro, thomas.lendacky, vasant.hegde,
suravee.suthikulpanit, aik
Cc: iommu, linux-kernel, wei.w.wang
AMD Secure Memory Encryption (SME) marks individual memory pages as
encrypted by setting the C-bit in page table entries. According to the
AMD APM,any pages corresponding to MMIO addresses must be configured
with the C-bit clear.
The current *_iommu_set_prot() implementation sets the C-bit on all PTEs
in the IOMMU page tables. This is incorrect for PTEs backed by MMIO, and
can break PCIe peer-to-peer communication when IOVA is used. Fix this by
avoiding the C-bit for MMIO-backed mappings.
For amdv2 IOMMU page tables, there is a usage scenario for GVA->GPA
mappings, and for the trusted MMIO in the TEE-IO case, the C-bit will need
to be added to GPA. However, SNP guests do not yet support vIOMMU, and the
trusted MMIO support is not ready in upstream. Adding the C-bit for trusted
MMIO can be considered once those features land.
Fixes: 879ced2bab1b ("iommupt: Add the AMD IOMMU v1 page table format")
Fixes: aef5de756ea8 ("iommupt: Add the x86 64 bit page table format")
Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Signed-off-by: Wei Wang <wei.w.wang@hotmail.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/iommu/generic_pt/fmt/amdv1.h | 3 ++-
drivers/iommu/generic_pt/fmt/x86_64.h | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/drivers/iommu/generic_pt/fmt/amdv1.h b/drivers/iommu/generic_pt/fmt/amdv1.h
index aa8e1a8ec95f..3b2c41d9654d 100644
--- a/drivers/iommu/generic_pt/fmt/amdv1.h
+++ b/drivers/iommu/generic_pt/fmt/amdv1.h
@@ -354,7 +354,8 @@ static inline int amdv1pt_iommu_set_prot(struct pt_common *common,
* Ideally we'd have an IOMMU_ENCRYPTED flag set by higher levels to
* control this. For now if the tables use sme_set then so do the ptes.
*/
- if (pt_feature(common, PT_FEAT_AMDV1_ENCRYPT_TABLES))
+ if (pt_feature(common, PT_FEAT_AMDV1_ENCRYPT_TABLES) &&
+ !(iommu_prot & IOMMU_MMIO))
pte = __sme_set(pte);
attrs->descriptor_bits = pte;
diff --git a/drivers/iommu/generic_pt/fmt/x86_64.h b/drivers/iommu/generic_pt/fmt/x86_64.h
index 210748d9d6e8..ed9a47cbb6e0 100644
--- a/drivers/iommu/generic_pt/fmt/x86_64.h
+++ b/drivers/iommu/generic_pt/fmt/x86_64.h
@@ -227,7 +227,8 @@ static inline int x86_64_pt_iommu_set_prot(struct pt_common *common,
* Ideally we'd have an IOMMU_ENCRYPTED flag set by higher levels to
* control this. For now if the tables use sme_set then so do the ptes.
*/
- if (pt_feature(common, PT_FEAT_X86_64_AMD_ENCRYPT_TABLES))
+ if (pt_feature(common, PT_FEAT_X86_64_AMD_ENCRYPT_TABLES) &&
+ !(iommu_prot & IOMMU_MMIO))
pte = __sme_set(pte);
attrs->descriptor_bits = pte;
--
2.51.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v4 2/2] vfio/type1: Set IOMMU_MMIO in dma->prot for MMIO-backed addresses
2025-12-16 16:13 [PATCH v4 0/2] iommu: Avoid setting C-bit for MMIO addresses Wei Wang
2025-12-16 16:13 ` [PATCH v4 1/2] iommupt: Do not set C-bit on MMIO backed PTEs Wei Wang
@ 2025-12-16 16:13 ` Wei Wang
2025-12-17 4:24 ` Alexey Kardashevskiy
1 sibling, 1 reply; 6+ messages in thread
From: Wei Wang @ 2025-12-16 16:13 UTC (permalink / raw)
To: jgg, kevin.tian, alex, joro, thomas.lendacky, vasant.hegde,
suravee.suthikulpanit, aik
Cc: iommu, linux-kernel, wei.w.wang
Before requesting the IOMMU driver to map an IOVA to a physical address,
set the IOMMU_MMIO flag in dma->prot when the physical address corresponds
to MMIO. This allows the IOMMU driver to handle MMIO mappings specially.
For example, on AMD CPUs with SME enabled, the IOMMU driver avoids setting
the C-bit if iommu_map() is called with IOMMU_MMIO set in prot. This
prevents issues with PCIe P2P communication when IOVA is used.
Signed-off-by: Wei Wang <wei.w.wang@hotmail.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
---
drivers/vfio/vfio_iommu_type1.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 5167bec14e36..dfe53da53b80 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -583,7 +583,7 @@ static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm,
* returned initial pfn are provided; subsequent pfns are contiguous.
*/
static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
- unsigned long npages, int prot, unsigned long *pfn,
+ unsigned long npages, int *prot, unsigned long *pfn,
struct vfio_batch *batch)
{
unsigned long pin_pages = min_t(unsigned long, npages, batch->capacity);
@@ -591,7 +591,7 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
unsigned int flags = 0;
long ret;
- if (prot & IOMMU_WRITE)
+ if (*prot & IOMMU_WRITE)
flags |= FOLL_WRITE;
mmap_read_lock(mm);
@@ -601,6 +601,7 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
*pfn = page_to_pfn(batch->pages[0]);
batch->size = ret;
batch->offset = 0;
+ *prot &= ~IOMMU_MMIO;
goto done;
} else if (!ret) {
ret = -EFAULT;
@@ -615,7 +616,7 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
unsigned long addr_mask;
ret = follow_fault_pfn(vma, mm, vaddr, pfn, &addr_mask,
- prot & IOMMU_WRITE);
+ *prot & IOMMU_WRITE);
if (ret == -EAGAIN)
goto retry;
@@ -623,6 +624,9 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
if (is_invalid_reserved_pfn(*pfn)) {
unsigned long epfn;
+ if (vma->vm_flags & VM_IO)
+ *prot |= IOMMU_MMIO;
+
epfn = (*pfn | (~addr_mask >> PAGE_SHIFT)) + 1;
ret = min_t(long, npages, epfn - *pfn);
} else {
@@ -709,7 +713,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
cond_resched();
/* Empty batch, so refill it. */
- ret = vaddr_get_pfns(mm, vaddr, npage, dma->prot,
+ ret = vaddr_get_pfns(mm, vaddr, npage, &dma->prot,
&pfn, batch);
if (ret < 0)
goto unpin_out;
@@ -850,7 +854,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
vfio_batch_init_single(&batch);
- ret = vaddr_get_pfns(mm, vaddr, 1, dma->prot, pfn_base, &batch);
+ ret = vaddr_get_pfns(mm, vaddr, 1, &dma->prot, pfn_base, &batch);
if (ret != 1)
goto out;
--
2.51.0
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 2/2] vfio/type1: Set IOMMU_MMIO in dma->prot for MMIO-backed addresses
2025-12-16 16:13 ` [PATCH v4 2/2] vfio/type1: Set IOMMU_MMIO in dma->prot for MMIO-backed addresses Wei Wang
@ 2025-12-17 4:24 ` Alexey Kardashevskiy
2025-12-22 2:14 ` Wei Wang
[not found] ` <a8a7d0d0-3bb4-4f87-bc82-4e6387481974@hotmail.com>
0 siblings, 2 replies; 6+ messages in thread
From: Alexey Kardashevskiy @ 2025-12-17 4:24 UTC (permalink / raw)
To: Wei Wang, jgg, kevin.tian, alex, joro, thomas.lendacky,
vasant.hegde, suravee.suthikulpanit
Cc: iommu, linux-kernel
On 17/12/25 03:13, Wei Wang wrote:
> Before requesting the IOMMU driver to map an IOVA to a physical address,
> set the IOMMU_MMIO flag in dma->prot when the physical address corresponds
> to MMIO. This allows the IOMMU driver to handle MMIO mappings specially.
> For example, on AMD CPUs with SME enabled, the IOMMU driver avoids setting
> the C-bit if iommu_map() is called with IOMMU_MMIO set in prot. This
> prevents issues with PCIe P2P communication when IOVA is used.
>
> Signed-off-by: Wei Wang <wei.w.wang@hotmail.com>
> Reviewed-by: Kevin Tian <kevin.tian@intel.com>
> ---
> drivers/vfio/vfio_iommu_type1.c | 14 +++++++++-----
> 1 file changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
> index 5167bec14e36..dfe53da53b80 100644
> --- a/drivers/vfio/vfio_iommu_type1.c
> +++ b/drivers/vfio/vfio_iommu_type1.c
> @@ -583,7 +583,7 @@ static int follow_fault_pfn(struct vm_area_struct *vma, struct mm_struct *mm,
> * returned initial pfn are provided; subsequent pfns are contiguous.
> */
> static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
> - unsigned long npages, int prot, unsigned long *pfn,
> + unsigned long npages, int *prot, unsigned long *pfn,
> struct vfio_batch *batch)
> {
> unsigned long pin_pages = min_t(unsigned long, npages, batch->capacity);
> @@ -591,7 +591,7 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
> unsigned int flags = 0;
> long ret;
>
> - if (prot & IOMMU_WRITE)
> + if (*prot & IOMMU_WRITE)
> flags |= FOLL_WRITE;
>
> mmap_read_lock(mm);
> @@ -601,6 +601,7 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
> *pfn = page_to_pfn(batch->pages[0]);
> batch->size = ret;
> batch->offset = 0;
> + *prot &= ~IOMMU_MMIO;
Do you expect IOMMU_MMIO here, why?
Then, what if this vaddr_get_pfns() called with vaddr which is some RAM immediately followed by MMIO? The whole vfio_dma descriptor will get IOMMU_MMIO, hardly desirable (also quite unlikely though).
Thanks,
> goto done;
> } else if (!ret) {
> ret = -EFAULT;
> @@ -615,7 +616,7 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
> unsigned long addr_mask;
>
> ret = follow_fault_pfn(vma, mm, vaddr, pfn, &addr_mask,
> - prot & IOMMU_WRITE);
> + *prot & IOMMU_WRITE);
> if (ret == -EAGAIN)
> goto retry;
>
> @@ -623,6 +624,9 @@ static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
> if (is_invalid_reserved_pfn(*pfn)) {
> unsigned long epfn;
>
> + if (vma->vm_flags & VM_IO)
> + *prot |= IOMMU_MMIO;
> +
> epfn = (*pfn | (~addr_mask >> PAGE_SHIFT)) + 1;
> ret = min_t(long, npages, epfn - *pfn);
> } else {
> @@ -709,7 +713,7 @@ static long vfio_pin_pages_remote(struct vfio_dma *dma, unsigned long vaddr,
> cond_resched();
>
> /* Empty batch, so refill it. */
> - ret = vaddr_get_pfns(mm, vaddr, npage, dma->prot,
> + ret = vaddr_get_pfns(mm, vaddr, npage, &dma->prot,
> &pfn, batch);
> if (ret < 0)
> goto unpin_out;
> @@ -850,7 +854,7 @@ static int vfio_pin_page_external(struct vfio_dma *dma, unsigned long vaddr,
>
> vfio_batch_init_single(&batch);
>
> - ret = vaddr_get_pfns(mm, vaddr, 1, dma->prot, pfn_base, &batch);
> + ret = vaddr_get_pfns(mm, vaddr, 1, &dma->prot, pfn_base, &batch);
> if (ret != 1)
> goto out;
>
--
Alexey
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 2/2] vfio/type1: Set IOMMU_MMIO in dma->prot for MMIO-backed addresses
2025-12-17 4:24 ` Alexey Kardashevskiy
@ 2025-12-22 2:14 ` Wei Wang
[not found] ` <a8a7d0d0-3bb4-4f87-bc82-4e6387481974@hotmail.com>
1 sibling, 0 replies; 6+ messages in thread
From: Wei Wang @ 2025-12-22 2:14 UTC (permalink / raw)
To: Alexey Kardashevskiy, jgg, kevin.tian, alex, joro,
thomas.lendacky, vasant.hegde, suravee.suthikulpanit
Cc: iommu, linux-kernel
On 12/17/25 12:24 PM, Alexey Kardashevskiy wrote:
>
>
> On 17/12/25 03:13, Wei Wang wrote:
>> Before requesting the IOMMU driver to map an IOVA to a physical address,
>> set the IOMMU_MMIO flag in dma->prot when the physical address
>> corresponds
>> to MMIO. This allows the IOMMU driver to handle MMIO mappings specially.
>> For example, on AMD CPUs with SME enabled, the IOMMU driver avoids
>> setting
>> the C-bit if iommu_map() is called with IOMMU_MMIO set in prot. This
>> prevents issues with PCIe P2P communication when IOVA is used.
>>
>> Signed-off-by: Wei Wang <wei.w.wang@hotmail.com>
>> Reviewed-by: Kevin Tian <kevin.tian@intel.com>
>> ---
>> drivers/vfio/vfio_iommu_type1.c | 14 +++++++++-----
>> 1 file changed, 9 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/
>> vfio_iommu_type1.c
>> index 5167bec14e36..dfe53da53b80 100644
>> --- a/drivers/vfio/vfio_iommu_type1.c
>> +++ b/drivers/vfio/vfio_iommu_type1.c
>> @@ -583,7 +583,7 @@ static int follow_fault_pfn(struct vm_area_struct
>> *vma, struct mm_struct *mm,
>> * returned initial pfn are provided; subsequent pfns are contiguous.
>> */
>> static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
>> - unsigned long npages, int prot, unsigned long *pfn,
>> + unsigned long npages, int *prot, unsigned long *pfn,
>> struct vfio_batch *batch)
>> {
>> unsigned long pin_pages = min_t(unsigned long, npages, batch-
>> >capacity);
>> @@ -591,7 +591,7 @@ static long vaddr_get_pfns(struct mm_struct *mm,
>> unsigned long vaddr,
>> unsigned int flags = 0;
>> long ret;
>> - if (prot & IOMMU_WRITE)
>> + if (*prot & IOMMU_WRITE)
>> flags |= FOLL_WRITE;
>> mmap_read_lock(mm);
>> @@ -601,6 +601,7 @@ static long vaddr_get_pfns(struct mm_struct *mm,
>> unsigned long vaddr,
>> *pfn = page_to_pfn(batch->pages[0]);
>> batch->size = ret;
>> batch->offset = 0;
>> + *prot &= ~IOMMU_MMIO;
>
>
> Do you expect IOMMU_MMIO here, why?
>
> Then, what if this vaddr_get_pfns() called with vaddr which is some RAM
> immediately followed by MMIO? The whole vfio_dma descriptor will get
> IOMMU_MMIO, hardly desirable (also quite unlikely though).
>
Yeah, thanks for pointing this out. The current implementation logic
allows the adjacent RAM and MMIO address ranges to be handled via
separate vfio_iommu_map() calls (in vfio_pin_map_dma()). Given the
issues you mentioned above, it might not be appropriate to clear the
IOMMU_MMIO flag here. I’m considering removing the above IOMMU_MMIO
flag clearing in vaddr_get_pfns() and adding the following changes
to vfio_pin_pages_remote():
out:
dma->has_rsvd |= rsvd;
+ if (!rsvd)
+ dma->prot &= ~IOMMU_MMIO;
ret = vfio_lock_acct(dma, lock_acct, false);
unpin_out:
if (ret < 0) {
if (pinned && !rsvd) {
for (pfn = *pfn_base ; pinned ; pfn++, pinned--)
put_pfn(pfn, dma->prot);
}
vfio_batch_unpin(batch, dma);
return ret;
}
return pinned;
}
*pfn_base is the address that will be returned to vfio_pin_map_dma() to
do vfio_iommu_map, and rsvd indicates the status of *pfn_base — MMIO
addresses are guaranteed to have rsvd=true. Thus, when !rsvd, *pfn_base
is not MMIO, and the IOMMU_MMIO flag needs to be cleared.
Then revisit the two corner cases:
- RAM immediately followed by MMIO: The first call to vaddr_get_pfns()
will set *pfn_base to a RAM physical address, and rsvd will be updated
to false. In the subsequent iteration of the “while (npage)” loop,
vaddr_get_pfns() will detect an MMIO address and update dma->prot to
include IOMMU_MMIO. Since the value returned to vfio_pin_map_dma()
corresponds to a RAM’s pfn (with rsvd=false) obtained in the first call
above, the IOMMU_MMIO flag will be cleared when going to “out:”.
- MMIO immediately followed by RAM: The first vaddr_get_pfns()
invocation will identify an MMIO address, set *pfn_base to this MMIO
address, and then mark rsvd=true. When going to “out:”, the IOMMU_MMIO
flag will remain set.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH v4 2/2] vfio/type1: Set IOMMU_MMIO in dma->prot for MMIO-backed addresses
[not found] ` <a8a7d0d0-3bb4-4f87-bc82-4e6387481974@hotmail.com>
@ 2026-01-13 11:06 ` Wei Wang
0 siblings, 0 replies; 6+ messages in thread
From: Wei Wang @ 2026-01-13 11:06 UTC (permalink / raw)
To: Alexey Kardashevskiy, jgg, kevin.tian, alex, joro,
thomas.lendacky, vasant.hegde, suravee.suthikulpanit
Cc: iommu, linux-kernel
On 12/22/25 10:14 AM, Wei Wang wrote:
> On 12/17/25 12:24 PM, Alexey Kardashevskiy wrote:
>>
>>
>> On 17/12/25 03:13, Wei Wang wrote:
>>> Before requesting the IOMMU driver to map an IOVA to a physical address,
>>> set the IOMMU_MMIO flag in dma->prot when the physical address
>>> corresponds
>>> to MMIO. This allows the IOMMU driver to handle MMIO mappings specially.
>>> For example, on AMD CPUs with SME enabled, the IOMMU driver avoids
>>> setting
>>> the C-bit if iommu_map() is called with IOMMU_MMIO set in prot. This
>>> prevents issues with PCIe P2P communication when IOVA is used.
>>>
>>> Signed-off-by: Wei Wang <wei.w.wang@hotmail.com>
>>> Reviewed-by: Kevin Tian <kevin.tian@intel.com>
>>> ---
>>> drivers/vfio/vfio_iommu_type1.c | 14 +++++++++-----
>>> 1 file changed, 9 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/
>>> vfio_iommu_type1.c
>>> index 5167bec14e36..dfe53da53b80 100644
>>> --- a/drivers/vfio/vfio_iommu_type1.c
>>> +++ b/drivers/vfio/vfio_iommu_type1.c
>>> @@ -583,7 +583,7 @@ static int follow_fault_pfn(struct vm_area_struct
>>> *vma, struct mm_struct *mm,
>>> * returned initial pfn are provided; subsequent pfns are contiguous.
>>> */
>>> static long vaddr_get_pfns(struct mm_struct *mm, unsigned long vaddr,
>>> - unsigned long npages, int prot, unsigned long *pfn,
>>> + unsigned long npages, int *prot, unsigned long *pfn,
>>> struct vfio_batch *batch)
>>> {
>>> unsigned long pin_pages = min_t(unsigned long, npages, batch-
>>> >capacity);
>>> @@ -591,7 +591,7 @@ static long vaddr_get_pfns(struct mm_struct *mm,
>>> unsigned long vaddr,
>>> unsigned int flags = 0;
>>> long ret;
>>> - if (prot & IOMMU_WRITE)
>>> + if (*prot & IOMMU_WRITE)
>>> flags |= FOLL_WRITE;
>>> mmap_read_lock(mm);
>>> @@ -601,6 +601,7 @@ static long vaddr_get_pfns(struct mm_struct *mm,
>>> unsigned long vaddr,
>>> *pfn = page_to_pfn(batch->pages[0]);
>>> batch->size = ret;
>>> batch->offset = 0;
>>> + *prot &= ~IOMMU_MMIO;
>>
>>
>> Do you expect IOMMU_MMIO here, why?
>>
>> Then, what if this vaddr_get_pfns() called with vaddr which is some
>> RAM immediately followed by MMIO? The whole vfio_dma descriptor will
>> get IOMMU_MMIO, hardly desirable (also quite unlikely though).
>>
>
> Yeah, thanks for pointing this out. The current implementation logic
> allows the adjacent RAM and MMIO address ranges to be handled via
> separate vfio_iommu_map() calls (in vfio_pin_map_dma()). Given the
> issues you mentioned above, it might not be appropriate to clear the
> IOMMU_MMIO flag here. I’m considering removing the above IOMMU_MMIO
> flag clearing in vaddr_get_pfns() and adding the following changes
> to vfio_pin_pages_remote():
>
> out:
> dma->has_rsvd |= rsvd;
> + if (!rsvd)
> + dma->prot &= ~IOMMU_MMIO;
> ret = vfio_lock_acct(dma, lock_acct, false);
>
> unpin_out:
> if (ret < 0) {
> if (pinned && !rsvd) {
> for (pfn = *pfn_base ; pinned ; pfn++, pinned--)
> put_pfn(pfn, dma->prot);
> }
> vfio_batch_unpin(batch, dma);
>
> return ret;
> }
>
> return pinned;
> }
>
> *pfn_base is the address that will be returned to vfio_pin_map_dma() to
> do vfio_iommu_map, and rsvd indicates the status of *pfn_base — MMIO
> addresses are guaranteed to have rsvd=true. Thus, when !rsvd, *pfn_base
> is not MMIO, and the IOMMU_MMIO flag needs to be cleared.
>
> Then revisit the two corner cases:
> - RAM immediately followed by MMIO: The first call to vaddr_get_pfns()
> will set *pfn_base to a RAM physical address, and rsvd will be updated
> to false. In the subsequent iteration of the “while (npage)” loop,
> vaddr_get_pfns() will detect an MMIO address and update dma->prot to
> include IOMMU_MMIO. Since the value returned to vfio_pin_map_dma()
> corresponds to a RAM’s pfn (with rsvd=false) obtained in the first call
> above, the IOMMU_MMIO flag will be cleared when going to “out:”.
>
> - MMIO immediately followed by RAM: The first vaddr_get_pfns()
> invocation will identify an MMIO address, set *pfn_base to this MMIO
> address, and then mark rsvd=true. When going to “out:”, the IOMMU_MMIO
> flag will remain set.
Hi Alexey, any thoughts on the changes above?
If there are no objections from others, I'll send a new version with
that update.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-01-13 11:07 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-16 16:13 [PATCH v4 0/2] iommu: Avoid setting C-bit for MMIO addresses Wei Wang
2025-12-16 16:13 ` [PATCH v4 1/2] iommupt: Do not set C-bit on MMIO backed PTEs Wei Wang
2025-12-16 16:13 ` [PATCH v4 2/2] vfio/type1: Set IOMMU_MMIO in dma->prot for MMIO-backed addresses Wei Wang
2025-12-17 4:24 ` Alexey Kardashevskiy
2025-12-22 2:14 ` Wei Wang
[not found] ` <a8a7d0d0-3bb4-4f87-bc82-4e6387481974@hotmail.com>
2026-01-13 11:06 ` Wei Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®