[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [win-pv-devel] [PATCH 1/2] Add foreign page mapping functions to the GNTTAB interface



On 2015-09-04 10:58, Paul Durrant wrote:
>> -----Original Message-----
>> From: win-pv-devel-bounces@xxxxxxxxxxxxxxxxxxxx [mailto:win-pv-devel-
>> bounces@xxxxxxxxxxxxxxxxxxxx] On Behalf Of Rafal Wojdyla
>> Sent: 25 August 2015 17:16
>> To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
>> Subject: [win-pv-devel] [PATCH 1/2] Add foreign page mapping functions to
>> the GNTTAB interface
>>
>> GNTTAB interface now includes functions to map and unmap memory pages
>> granted by a foreign domain. The page(s) are mapped under an address
>> allocated from the PCI BAR space.
>>
>> Signed-off-by: RafaÅ WojdyÅa <omeg@xxxxxxxxxxxxxxxxxxxxxx>
>> ---
>>  include/gnttab_interface.h |  62 +++++++++++++++++++++++-
>>  include/xen.h              |  19 ++++++++
>>  src/xen/grant_table.c      |  85 +++++++++++++++++++++++++++++++++
>>  src/xenbus/gnttab.c        | 114
>> +++++++++++++++++++++++++++++++++++++++++++++
>>  4 files changed, 278 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/gnttab_interface.h b/include/gnttab_interface.h
>> index d29440a..0016888 100644
>> --- a/include/gnttab_interface.h
>> +++ b/include/gnttab_interface.h
>> @@ -163,6 +163,47 @@ typedef VOID
>>      IN  PXENBUS_GNTTAB_CACHE    Cache
>>      );
>>
>> +/*! \typedef XENBUS_GNTTAB_MAP_FOREIGN_PAGES
>> +    \brief Map foreign memory pages into the system address space
>> +
>> +    \param Interface The interface header
>> +    \param Domain The domid of the foreign domain that granted the pages
>> +    \param NumberPages Number of pages to map
>> +    \param References Array of grant reference numbers shared by the
>> foreign domain
>> +    \param ReadOnly If TRUE, pages are mapped with read-only access
>> +    \param Address The physical address that the foreign pages are mapped
>> under
>> +    (allocated from the PCI IO space)
> 
> They need not be - we could decrease_reservation out some RAM - so I'd see 
> this as an implementation detail rather than something to be documented in 
> the interface.
> 
True.

>> +    \param Handles An array of tracking numbers that represent the mapping
>> +    of each individual page
>> + */
> 
> It's kind of ugly to expose Xen's grant mapping handles out through this 
> interface. Could we do better? I think we could: How about using a hash table 
> of base addresses to grant map handles? Also, that means the unmap-pages 
> function only need take the base address; no need for number of pages or 
> handle array. That makes the functions look for like a malloc()/free() pair 
> which I think is nicer.
> 
Agreed. In my current code xeniface does most of that encapsulation but your 
approach makes more sense.
>> +
>> +typedef NTSTATUS
>> +(*XENBUS_GNTTAB_MAP_FOREIGN_PAGES)(
>> +    IN  PINTERFACE              Interface,
>> +    IN  USHORT                  Domain,
>> +    IN  ULONG                   NumberPages,
>> +    IN  PULONG                  References,
>> +    IN  BOOLEAN                 ReadOnly,
>> +    OUT PHYSICAL_ADDRESS        *Address,
>> +    OUT ULONG                   *Handles
>> +    );
>> +
>> +/*! \typedef XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES
>> +    \brief Unmap foreign memory pages from the system address space
>> +
>> +    \param Interface The interface header
>> +    \param NumberPages Number of pages to unmap
>> +    \param Address The physical address that the foreign pages are mapped
>> under
>> +    \param Handles An array of tracking numbers that represent the mapping
>> + */
>> +typedef NTSTATUS
>> +(*XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES)(
>> +    IN  PINTERFACE              Interface,
>> +    IN  ULONG                   NumberPages,
>> +    IN  PHYSICAL_ADDRESS        Address,
>> +    IN  PULONG                  Handles
>> +    );
>> +
>>  // {763679C5-E5C2-4A6D-8B88-6BB02EC42D8E}
>>  DEFINE_GUID(GUID_XENBUS_GNTTAB_INTERFACE,
>>  0x763679c5, 0xe5c2, 0x4a6d, 0x8b, 0x88, 0x6b, 0xb0, 0x2e, 0xc4, 0x2d, 0x8e);
>> @@ -182,7 +223,24 @@ struct _XENBUS_GNTTAB_INTERFACE_V1 {
>>      XENBUS_GNTTAB_DESTROY_CACHE         GnttabDestroyCache;
>>  };
>>
>> -typedef struct _XENBUS_GNTTAB_INTERFACE_V1
>> XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNTTAB_INTERFACE;
>> +/*! \struct _XENBUS_GNTTAB_INTERFACE_V2
>> +    \brief GNTTAB interface version 2 (added map/unmap foreign pages)
>> +    \ingroup interfaces
>> + */
>> +struct _XENBUS_GNTTAB_INTERFACE_V2 {
>> +    INTERFACE                           Interface;
>> +    XENBUS_GNTTAB_ACQUIRE               GnttabAcquire;
>> +    XENBUS_GNTTAB_RELEASE               GnttabRelease;
>> +    XENBUS_GNTTAB_CREATE_CACHE          GnttabCreateCache;
>> +    XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS
>> GnttabPermitForeignAccess;
>> +    XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS
>> GnttabRevokeForeignAccess;
>> +    XENBUS_GNTTAB_GET_REFERENCE         GnttabGetReference;
>> +    XENBUS_GNTTAB_DESTROY_CACHE         GnttabDestroyCache;
>> +    XENBUS_GNTTAB_MAP_FOREIGN_PAGES     GnttabMapForeignPages;
>> +    XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES
>> GnttabUnmapForeignPages;
>> +};
>> +
>> +typedef struct _XENBUS_GNTTAB_INTERFACE_V2
>> XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNTTAB_INTERFACE;
>>
>>  /*! \def XENBUS_GNTTAB
>>      \brief Macro at assist in method invocation
>> @@ -193,7 +251,7 @@ typedef struct _XENBUS_GNTTAB_INTERFACE_V1
>> XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNT
>>  #endif  // _WINDLL
>>
>>  #define XENBUS_GNTTAB_INTERFACE_VERSION_MIN 1
>> -#define XENBUS_GNTTAB_INTERFACE_VERSION_MAX 1
>> +#define XENBUS_GNTTAB_INTERFACE_VERSION_MAX 2
>>
>>  #endif  // _XENBUS_GNTTAB_INTERFACE_H
>>
>> diff --git a/include/xen.h b/include/xen.h
>> index 6007582..23c7ac0 100644
>> --- a/include/xen.h
>> +++ b/include/xen.h
>> @@ -258,6 +258,25 @@ GrantTableCopy(
>>      IN  ULONG               Count
>>      );
>>
>> +__checkReturn
>> +XEN_API
>> +NTSTATUS
>> +GrantTableMapForeignPage(
>> +    IN  USHORT                  Domain,
>> +    IN  ULONG                   GrantRef,
>> +    IN  PHYSICAL_ADDRESS        Address,
>> +    IN  BOOLEAN                 ReadOnly,
>> +    OUT ULONG                   *Handle
>> +    );
>> +
>> +__checkReturn
>> +XEN_API
>> +NTSTATUS
>> +GrantTableUnmapForeignPage(
>> +    IN  ULONG                   Handle,
>> +    IN  PHYSICAL_ADDRESS        Address
>> +    );
>> +
>>  // SCHED
>>
>>  __checkReturn
>> diff --git a/src/xen/grant_table.c b/src/xen/grant_table.c
>> index 6facb3f..6450062 100644
>> --- a/src/xen/grant_table.c
>> +++ b/src/xen/grant_table.c
>> @@ -131,3 +131,88 @@ fail1:
>>
>>      return status;
>>  }
>> +
>> +__checkReturn
>> +XEN_API
>> +NTSTATUS
>> +GrantTableMapForeignPage(
>> +    IN  USHORT                  Domain,
>> +    IN  ULONG                   GrantRef,
>> +    IN  PHYSICAL_ADDRESS        Address,
>> +    IN  BOOLEAN                 ReadOnly,
>> +    OUT ULONG                   *Handle
>> +    )
>> +{
>> +    struct gnttab_map_grant_ref op;
>> +    LONG_PTR rc;
>> +    NTSTATUS status;
>> +
>> +    RtlZeroMemory(&op, sizeof(op));
>> +    op.dom = Domain;
>> +    op.ref = GrantRef;
>> +    op.flags = GNTMAP_host_map;
>> +    if (ReadOnly)
>> +        op.flags |= GNTMAP_readonly;
>> +    op.host_addr = Address.QuadPart;
>> +
>> +    rc = GrantTableOp(GNTTABOP_map_grant_ref, &op, 1);
>> +
>> +    if (rc < 0) {
>> +        ERRNO_TO_STATUS(-rc, status);
>> +        goto fail1;
>> +    }
>> +
>> +    if (op.status != GNTST_okay) {
>> +        status = STATUS_UNSUCCESSFUL;
>> +        goto fail2;
>> +    }
>> +
>> +    *Handle = op.handle;
>> +
>> +    return STATUS_SUCCESS;
>> +
>> +fail2:
>> +    Error("fail2: op.status = %d\n", op.status);
> 
> In general I've tried to keep 'Error' messages other than 'fail1:'  plain. 
> Rather than just setting status to unsuccessful and logging the raw grant 
> status here it would be nicer to have a GNTST_TO_STATUS() macro to set status 
> to something meaningful and then just log that in the 'fail1:' below.
Noted.
> 
>> +fail1:
>> +    Error("fail1 (%08x)\n", status);
>> +
>> +    return status;
>> +}
>> +
>> +__checkReturn
>> +XEN_API
>> +NTSTATUS
>> +GrantTableUnmapForeignPage(
>> +    IN  ULONG                   Handle,
>> +    IN  PHYSICAL_ADDRESS        Address
>> +    )
>> +{
>> +    struct gnttab_unmap_grant_ref op;
>> +    LONG_PTR rc;
>> +    NTSTATUS status;
>> +
>> +    RtlZeroMemory(&op, sizeof(op));
>> +    op.handle = Handle;
>> +    op.host_addr = Address.QuadPart;
>> +
>> +    rc = GrantTableOp(GNTTABOP_unmap_grant_ref, &op, 1);
>> +
>> +    if (rc < 0) {
>> +        ERRNO_TO_STATUS(-rc, status);
>> +        goto fail1;
>> +    }
>> +
>> +    if (op.status != GNTST_okay) {
>> +        status = STATUS_UNSUCCESSFUL;
>> +        goto fail2;
>> +    }
>> +
>> +    return STATUS_SUCCESS;
>> +
>> +fail2:
>> +    Error("op.status = %d\n", op.status);
> 
> Same here.
> 
>> +fail1:
>> +    Error("fail1 (%08x)\n", status);
>> +
>> +    return status;
>> +}
>> diff --git a/src/xenbus/gnttab.c b/src/xenbus/gnttab.c
>> index 165e38f..24d45af 100644
>> --- a/src/xenbus/gnttab.c
>> +++ b/src/xenbus/gnttab.c
>> @@ -534,6 +534,90 @@ GnttabGetReference(
>>      return (ULONG)Entry->Reference;
>>  }
>>
>> +static NTSTATUS
>> +GnttabMapForeignPages(
>> +    IN  PINTERFACE              Interface,
>> +    IN  USHORT                  Domain,
>> +    IN  ULONG                   NumberPages,
>> +    IN  PULONG                  References,
>> +    IN  BOOLEAN                 ReadOnly,
>> +    OUT PHYSICAL_ADDRESS        *Address,
>> +    OUT ULONG                   *Handles
>> +    )
>> +{
>> +    NTSTATUS                    status;
>> +    PXENBUS_GNTTAB_CONTEXT      Context = Interface->Context;
>> +    ULONG                       PageIndex;
>> +    PHYSICAL_ADDRESS            PageAddress;
>> +
>> +    status = FdoAllocateIoSpace(Context->Fdo, NumberPages * PAGE_SIZE,
>> Address);
>> +    if (!NT_SUCCESS(status))
>> +        goto fail1;
>> +
>> +    PageAddress.QuadPart = Address->QuadPart;
>> +
>> +    for (PageIndex = 0; PageIndex < NumberPages; PageIndex++) {
>> +        status = GrantTableMapForeignPage(Domain,
>> +                                          References[PageIndex],
>> +                                          PageAddress,
>> +                                          ReadOnly,
>> +                                          &(Handles[PageIndex]));
>> +        if (!NT_SUCCESS(status))
>> +            goto fail2;
>> +
>> +        PageAddress.QuadPart += PAGE_SIZE;
>> +    }
>> +
>> +    return STATUS_SUCCESS;
>> +
>> +fail2:
>> +    Error("fail2: PageIndex %lu, PageAddress %p, Handle %lu\n", PageIndex,
>> PageAddress.QuadPart, Handles[PageIndex]);
>> +
>> +    while (PageIndex > 0) {
>> +        --PageIndex;
>> +        PageAddress.QuadPart -= PAGE_SIZE;
>> +
>> ASSERT(NT_SUCCESS(GrantTableUnmapForeignPage(Handles[PageIndex],
>> PageAddress)));
>> +    }
>> +
>> +    FdoFreeIoSpace(Context->Fdo, *Address, NumberPages * PAGE_SIZE);
>> +
>> +fail1:
>> +    Error("fail1: (%08x)\n", status);
>> +    return status;
>> +}
>> +
>> +static NTSTATUS
>> +GnttabUnmapForeignPages(
>> +    IN  PINTERFACE              Interface,
>> +    IN  ULONG                   NumberPages,
>> +    IN  PHYSICAL_ADDRESS        Address,
>> +    IN  PULONG                  Handles
>> +    )
>> +{
>> +    NTSTATUS                    status;
>> +    PXENBUS_GNTTAB_CONTEXT      Context = Interface->Context;
>> +    ULONG                       PageIndex;
>> +    PHYSICAL_ADDRESS            PageAddress;
>> +
>> +    PageAddress.QuadPart = Address.QuadPart;
>> +
>> +    for (PageIndex = 0; PageIndex < NumberPages; PageIndex++) {
>> +        status = GrantTableUnmapForeignPage(Handles[PageIndex],
>> PageAddress);
>> +        if (!NT_SUCCESS(status))
>> +            goto fail1;
>> +
>> +        PageAddress.QuadPart += PAGE_SIZE;
>> +    }
>> +
>> +    FdoFreeIoSpace(Context->Fdo, Address, NumberPages * PAGE_SIZE);
>> +    return STATUS_SUCCESS;
>> +
>> +fail1:
>> +    Error("fail1: (%08x), leaking memory at %p, size 0x%lx. PageIndex = %lu,
>> PageAddress = %p, Handle = %lu\n",
>> +          status, Address.QuadPart, NumberPages * PAGE_SIZE, PageIndex,
>> PageAddress.QuadPart, Handles[PageIndex]);
> 
> Hmm. What do we want to do on an unmap failure? I suspect such a failure 
> probably means something has gone pretty disastrously wrong somewhere. We 
> should probably bugcheck and let Xen clean up, otherwise we're potentially 
> preventing another domain from dying.
> 
Yeah, failures with mapping/unmapping should probably be fatal. I've never 
encountered any so it's probably safer to just bugcheck.

>   Paul
> 
>> +    return status;
>> +}
>> +
>>  static VOID
>>  GnttabSuspendCallbackEarly(
>>      IN  PVOID               Argument
>> @@ -789,6 +873,19 @@ static struct _XENBUS_GNTTAB_INTERFACE_V1
>> GnttabInterfaceVersion1 = {
>>      GnttabDestroyCache
>>  };
>>
>> +static struct _XENBUS_GNTTAB_INTERFACE_V2   GnttabInterfaceVersion2 =
>> {
>> +    { sizeof(struct _XENBUS_GNTTAB_INTERFACE_V2), 2, NULL, NULL, NULL
>> },
>> +    GnttabAcquire,
>> +    GnttabRelease,
>> +    GnttabCreateCache,
>> +    GnttabPermitForeignAccess,
>> +    GnttabRevokeForeignAccess,
>> +    GnttabGetReference,
>> +    GnttabDestroyCache,
>> +    GnttabMapForeignPages,
>> +    GnttabUnmapForeignPages
>> +};
>> +
>>  NTSTATUS
>>  GnttabInitialize(
>>      IN  PXENBUS_FDO             Fdo,
>> @@ -878,6 +975,23 @@ GnttabGetInterface(
>>          status = STATUS_SUCCESS;
>>          break;
>>      }
>> +    case 2: {
>> +        struct _XENBUS_GNTTAB_INTERFACE_V2  *GnttabInterface;
>> +
>> +        GnttabInterface = (struct _XENBUS_GNTTAB_INTERFACE_V2
>> *)Interface;
>> +
>> +        status = STATUS_BUFFER_OVERFLOW;
>> +        if (Size < sizeof(struct _XENBUS_GNTTAB_INTERFACE_V2))
>> +            break;
>> +
>> +        *GnttabInterface = GnttabInterfaceVersion2;
>> +
>> +        ASSERT3U(Interface->Version, ==, Version);
>> +        Interface->Context = Context;
>> +
>> +        status = STATUS_SUCCESS;
>> +        break;
>> +    }
>>      default:
>>          status = STATUS_NOT_SUPPORTED;
>>          break;
>>

Thanks for the input, I'll send a revised version in a few days.

-- 
RafaÅ WojdyÅa
Qubes Tools for Windows developer
https://www.qubes-os.org/

_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.