diff mbox

[v3,3/3] vfio: Fix 128 bit handling

Message ID 1377170965-9905-4-git-send-email-aik@ozlabs.ru
State New
Headers show

Commit Message

Alexey Kardashevskiy Aug. 22, 2013, 11:29 a.m. UTC
Upcoming VFIO on SPAPR PPC64 support will initialize the IOMMU
memory region with UINT64_MAX (2^64 bytes) size so int128_get64()
will assert.

The patch takes care of this check. The existing type1 IOMMU code
is not expected to map all 64 bits of RAM so the patch does not
touch that part.

Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
---
Changes:
v2:
* used new function int128_exts64()
---
 hw/misc/vfio.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

Comments

Alex Williamson Aug. 28, 2013, 3:18 p.m. UTC | #1
On Thu, 2013-08-22 at 21:29 +1000, Alexey Kardashevskiy wrote:
> Upcoming VFIO on SPAPR PPC64 support will initialize the IOMMU
> memory region with UINT64_MAX (2^64 bytes) size so int128_get64()
> will assert.
> 
> The patch takes care of this check. The existing type1 IOMMU code
> is not expected to map all 64 bits of RAM so the patch does not
> touch that part.
> 
> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> ---
> Changes:
> v2:
> * used new function int128_exts64()
> ---
>  hw/misc/vfio.c | 11 ++++++++---
>  1 file changed, 8 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
> index dfe3a80..3878fc7 100644
> --- a/hw/misc/vfio.c
> +++ b/hw/misc/vfio.c
> @@ -1920,6 +1920,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
>      VFIOContainer *container = container_of(listener, VFIOContainer,
>                                              iommu_data.listener);
>      hwaddr iova, end;
> +    Int128 llend;
>      void *vaddr;
>      int ret;
>  
> @@ -1940,13 +1941,17 @@ static void vfio_listener_region_add(MemoryListener *listener,
>      }
>  
>      iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
> -    end = (section->offset_within_address_space + int128_get64(section->size)) &
> -          TARGET_PAGE_MASK;
> +    llend = int128_make64(section->offset_within_address_space);
> +    llend = int128_add(llend, section->size);
> +    llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
>  
> -    if (iova >= end) {
> +    if (int128_ge(int128_make64(iova), llend)) {
>          return;
>      }
>  
> +    end = (section->offset_within_address_space + int128_get64(section->size)) &
> +          TARGET_PAGE_MASK;
> +

I'm confused, we build an Int128 version of end above for the
comparison, why isn't this just:

end = int128_get64(llend);

here?  Thanks,

Alex

>      vaddr = memory_region_get_ram_ptr(section->mr) +
>              section->offset_within_region +
>              (iova - section->offset_within_address_space);
Alexey Kardashevskiy Aug. 29, 2013, 1:03 a.m. UTC | #2
On 08/29/2013 01:18 AM, Alex Williamson wrote:
> On Thu, 2013-08-22 at 21:29 +1000, Alexey Kardashevskiy wrote:
>> Upcoming VFIO on SPAPR PPC64 support will initialize the IOMMU
>> memory region with UINT64_MAX (2^64 bytes) size so int128_get64()
>> will assert.
>>
>> The patch takes care of this check. The existing type1 IOMMU code
>> is not expected to map all 64 bits of RAM so the patch does not
>> touch that part.
>>
>> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
>> ---
>> Changes:
>> v2:
>> * used new function int128_exts64()
>> ---
>>  hw/misc/vfio.c | 11 ++++++++---
>>  1 file changed, 8 insertions(+), 3 deletions(-)
>>
>> diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
>> index dfe3a80..3878fc7 100644
>> --- a/hw/misc/vfio.c
>> +++ b/hw/misc/vfio.c
>> @@ -1920,6 +1920,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
>>      VFIOContainer *container = container_of(listener, VFIOContainer,
>>                                              iommu_data.listener);
>>      hwaddr iova, end;
>> +    Int128 llend;
>>      void *vaddr;
>>      int ret;
>>  
>> @@ -1940,13 +1941,17 @@ static void vfio_listener_region_add(MemoryListener *listener,
>>      }
>>  
>>      iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
>> -    end = (section->offset_within_address_space + int128_get64(section->size)) &
>> -          TARGET_PAGE_MASK;
>> +    llend = int128_make64(section->offset_within_address_space);
>> +    llend = int128_add(llend, section->size);
>> +    llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
>>  
>> -    if (iova >= end) {
>> +    if (int128_ge(int128_make64(iova), llend)) {
>>          return;
>>      }
>>  
>> +    end = (section->offset_within_address_space + int128_get64(section->size)) &
>> +          TARGET_PAGE_MASK;
>> +
> 
> I'm confused, we build an Int128 version of end above for the
> comparison, why isn't this just:
> 
> end = int128_get64(llend);


section->size for IOMMU memory region I have on spapr-vfio is 2^64 so
int128_get64() fails.


> here?  Thanks,
> 
> Alex
> 
>>      vaddr = memory_region_get_ram_ptr(section->mr) +
>>              section->offset_within_region +
>>              (iova - section->offset_within_address_space);
> 
> 
>
Alex Williamson Aug. 29, 2013, 1:42 a.m. UTC | #3
On Thu, 2013-08-29 at 11:03 +1000, Alexey Kardashevskiy wrote:
> On 08/29/2013 01:18 AM, Alex Williamson wrote:
> > On Thu, 2013-08-22 at 21:29 +1000, Alexey Kardashevskiy wrote:
> >> Upcoming VFIO on SPAPR PPC64 support will initialize the IOMMU
> >> memory region with UINT64_MAX (2^64 bytes) size so int128_get64()
> >> will assert.
> >>
> >> The patch takes care of this check. The existing type1 IOMMU code
> >> is not expected to map all 64 bits of RAM so the patch does not
> >> touch that part.
> >>
> >> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
> >> ---
> >> Changes:
> >> v2:
> >> * used new function int128_exts64()
> >> ---
> >>  hw/misc/vfio.c | 11 ++++++++---
> >>  1 file changed, 8 insertions(+), 3 deletions(-)
> >>
> >> diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
> >> index dfe3a80..3878fc7 100644
> >> --- a/hw/misc/vfio.c
> >> +++ b/hw/misc/vfio.c
> >> @@ -1920,6 +1920,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
> >>      VFIOContainer *container = container_of(listener, VFIOContainer,
> >>                                              iommu_data.listener);
> >>      hwaddr iova, end;
> >> +    Int128 llend;
> >>      void *vaddr;
> >>      int ret;
> >>  
> >> @@ -1940,13 +1941,17 @@ static void vfio_listener_region_add(MemoryListener *listener,
> >>      }
> >>  
> >>      iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
> >> -    end = (section->offset_within_address_space + int128_get64(section->size)) &
> >> -          TARGET_PAGE_MASK;
> >> +    llend = int128_make64(section->offset_within_address_space);
> >> +    llend = int128_add(llend, section->size);
> >> +    llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
> >>  
> >> -    if (iova >= end) {
> >> +    if (int128_ge(int128_make64(iova), llend)) {
> >>          return;
> >>      }
> >>  
> >> +    end = (section->offset_within_address_space + int128_get64(section->size)) &
> >> +          TARGET_PAGE_MASK;
> >> +
> > 
> > I'm confused, we build an Int128 version of end above for the
> > comparison, why isn't this just:
> > 
> > end = int128_get64(llend);
> 
> 
> section->size for IOMMU memory region I have on spapr-vfio is 2^64 so
> int128_get64() fails.

But you're leaving code that does int128_get64(section->size)... how
does that not assert?  This patch is not maintainable.  We're seemingly
calculating the same value twice with no comment as to why.  A hwaddr
type end should be calculated from the Int128 rather than paying
attention to rollover in one place but not another.  Thanks,

Alex
Alexey Kardashevskiy Aug. 29, 2013, 2:26 a.m. UTC | #4
On 08/29/2013 11:42 AM, Alex Williamson wrote:
> On Thu, 2013-08-29 at 11:03 +1000, Alexey Kardashevskiy wrote:
>> On 08/29/2013 01:18 AM, Alex Williamson wrote:
>>> On Thu, 2013-08-22 at 21:29 +1000, Alexey Kardashevskiy wrote:
>>>> Upcoming VFIO on SPAPR PPC64 support will initialize the IOMMU
>>>> memory region with UINT64_MAX (2^64 bytes) size so int128_get64()
>>>> will assert.
>>>>
>>>> The patch takes care of this check. The existing type1 IOMMU code
>>>> is not expected to map all 64 bits of RAM so the patch does not
>>>> touch that part.
>>>>
>>>> Signed-off-by: Alexey Kardashevskiy <aik@ozlabs.ru>
>>>> ---
>>>> Changes:
>>>> v2:
>>>> * used new function int128_exts64()
>>>> ---
>>>>  hw/misc/vfio.c | 11 ++++++++---
>>>>  1 file changed, 8 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
>>>> index dfe3a80..3878fc7 100644
>>>> --- a/hw/misc/vfio.c
>>>> +++ b/hw/misc/vfio.c
>>>> @@ -1920,6 +1920,7 @@ static void vfio_listener_region_add(MemoryListener *listener,
>>>>      VFIOContainer *container = container_of(listener, VFIOContainer,
>>>>                                              iommu_data.listener);
>>>>      hwaddr iova, end;
>>>> +    Int128 llend;
>>>>      void *vaddr;
>>>>      int ret;
>>>>  
>>>> @@ -1940,13 +1941,17 @@ static void vfio_listener_region_add(MemoryListener *listener,
>>>>      }
>>>>  
>>>>      iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
>>>> -    end = (section->offset_within_address_space + int128_get64(section->size)) &
>>>> -          TARGET_PAGE_MASK;
>>>> +    llend = int128_make64(section->offset_within_address_space);
>>>> +    llend = int128_add(llend, section->size);
>>>> +    llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
>>>>  
>>>> -    if (iova >= end) {
>>>> +    if (int128_ge(int128_make64(iova), llend)) {
>>>>          return;
>>>>      }
>>>>  
>>>> +    end = (section->offset_within_address_space + int128_get64(section->size)) &
>>>> +          TARGET_PAGE_MASK;
>>>> +
>>>
>>> I'm confused, we build an Int128 version of end above for the
>>> comparison, why isn't this just:
>>>
>>> end = int128_get64(llend);
>>
>>
>> section->size for IOMMU memory region I have on spapr-vfio is 2^64 so
>> int128_get64() fails.
> 
> But you're leaving code that does int128_get64(section->size)... how
> does that not assert?


Right. I was planning to add my IOMMU stuff right before calculating @end.


> This patch is not maintainable.  We're seemingly
> calculating the same value twice with no comment as to why.  A hwaddr
> type end should be calculated from the Int128 rather than paying
> attention to rollover in one place but not another.  Thanks,

Yes, not maintainable... I guess I just have to convert @end to 128 bit as
well to have things consistent.
Paolo Bonzini Aug. 29, 2013, 6:29 a.m. UTC | #5
Il 29/08/2013 04:26, Alexey Kardashevskiy ha scritto:
> 
> Right. I was planning to add my IOMMU stuff right before calculating @end.

But then the non-IOMMU stuff can just use int128_get64, no?  So even if
this patch simply uses int128_get64, it is still a suitable basis for
adding IOMMU stuff.

Paolo

> 
>> > This patch is not maintainable.  We're seemingly
>> > calculating the same value twice with no comment as to why.  A hwaddr
>> > type end should be calculated from the Int128 rather than paying
>> > attention to rollover in one place but not another.  Thanks,
> Yes, not maintainable... I guess I just have to convert @end to 128 bit as
> well to have things consistent.
Alexey Kardashevskiy Aug. 29, 2013, 6:58 a.m. UTC | #6
On 08/29/2013 04:29 PM, Paolo Bonzini wrote:
> Il 29/08/2013 04:26, Alexey Kardashevskiy ha scritto:
>>
>> Right. I was planning to add my IOMMU stuff right before calculating @end.
> 
> But then the non-IOMMU stuff can just use int128_get64, no?  So even if
> this patch simply uses int128_get64, it is still a suitable basis for
> adding IOMMU stuff.

Suitable but ugly. What if before calling int128_get64, I test
section->size if it is <2^64 and only then do RAM part of this function?


> 
> Paolo
> 
>>
>>>> This patch is not maintainable.  We're seemingly
>>>> calculating the same value twice with no comment as to why.  A hwaddr
>>>> type end should be calculated from the Int128 rather than paying
>>>> attention to rollover in one place but not another.  Thanks,
>> Yes, not maintainable... I guess I just have to convert @end to 128 bit as
>> well to have things consistent.
>
Paolo Bonzini Aug. 29, 2013, 8:50 a.m. UTC | #7
Il 29/08/2013 08:58, Alexey Kardashevskiy ha scritto:
> On 08/29/2013 04:29 PM, Paolo Bonzini wrote:
>> Il 29/08/2013 04:26, Alexey Kardashevskiy ha scritto:
>>>
>>> Right. I was planning to add my IOMMU stuff right before calculating @end.
>>
>> But then the non-IOMMU stuff can just use int128_get64, no?  So even if
>> this patch simply uses int128_get64, it is still a suitable basis for
>> adding IOMMU stuff.
> 
> Suitable but ugly. What if before calling int128_get64, I test
> section->size if it is <2^64 and only then do RAM part of this function?

What if you just merge the two series together?

Paolo
Alexey Kardashevskiy Aug. 30, 2013, 6:15 a.m. UTC | #8
On 08/29/2013 06:50 PM, Paolo Bonzini wrote:
> Il 29/08/2013 08:58, Alexey Kardashevskiy ha scritto:
>> On 08/29/2013 04:29 PM, Paolo Bonzini wrote:
>>> Il 29/08/2013 04:26, Alexey Kardashevskiy ha scritto:
>>>>
>>>> Right. I was planning to add my IOMMU stuff right before calculating @end.
>>>
>>> But then the non-IOMMU stuff can just use int128_get64, no?  So even if
>>> this patch simply uses int128_get64, it is still a suitable basis for
>>> adding IOMMU stuff.
>>
>> Suitable but ugly. What if before calling int128_get64, I test
>> section->size if it is <2^64 and only then do RAM part of this function?
> 
> What if you just merge the two series together?

It will still be a function which can accept sections bigger than 2^64 and
theoretically call int128_get64() and assert. I would think that every time
when anyone calls int128_get64(), the value should be checked for <2^64. It
is like division by zero :)
Paolo Bonzini Aug. 30, 2013, 6:39 a.m. UTC | #9
Il 30/08/2013 08:15, Alexey Kardashevskiy ha scritto:
>> > What if you just merge the two series together?
> It will still be a function which can accept sections bigger than 2^64 and
> theoretically call int128_get64() and assert. I would think that every time
> when anyone calls int128_get64(), the value should be checked for <2^64. It
> is like division by zero :)

I understood that int128_get64() would be called only for RAM sections,
not for IOMMUs (and RAM sections cannot be 2^64-bytes large).  Is this
wrong?

Paolo
Alexey Kardashevskiy Aug. 30, 2013, 6:42 a.m. UTC | #10
On 08/30/2013 04:39 PM, Paolo Bonzini wrote:
> Il 30/08/2013 08:15, Alexey Kardashevskiy ha scritto:
>>>> What if you just merge the two series together?
>> It will still be a function which can accept sections bigger than 2^64 and
>> theoretically call int128_get64() and assert. I would think that every time
>> when anyone calls int128_get64(), the value should be checked for <2^64. It
>> is like division by zero :)
> 
> I understood that int128_get64() would be called only for RAM sections,
> not for IOMMUs (and RAM sections cannot be 2^64-bytes large).  Is this
> wrong?


This is correct but for people who do not know when and in what state it is
called, it can be confusing. Ok, I'll merge this with my vfio patches.
diff mbox

Patch

diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
index dfe3a80..3878fc7 100644
--- a/hw/misc/vfio.c
+++ b/hw/misc/vfio.c
@@ -1920,6 +1920,7 @@  static void vfio_listener_region_add(MemoryListener *listener,
     VFIOContainer *container = container_of(listener, VFIOContainer,
                                             iommu_data.listener);
     hwaddr iova, end;
+    Int128 llend;
     void *vaddr;
     int ret;
 
@@ -1940,13 +1941,17 @@  static void vfio_listener_region_add(MemoryListener *listener,
     }
 
     iova = TARGET_PAGE_ALIGN(section->offset_within_address_space);
-    end = (section->offset_within_address_space + int128_get64(section->size)) &
-          TARGET_PAGE_MASK;
+    llend = int128_make64(section->offset_within_address_space);
+    llend = int128_add(llend, section->size);
+    llend = int128_and(llend, int128_exts64(TARGET_PAGE_MASK));
 
-    if (iova >= end) {
+    if (int128_ge(int128_make64(iova), llend)) {
         return;
     }
 
+    end = (section->offset_within_address_space + int128_get64(section->size)) &
+          TARGET_PAGE_MASK;
+
     vaddr = memory_region_get_ram_ptr(section->mr) +
             section->offset_within_region +
             (iova - section->offset_within_address_space);