diff mbox

[v2,REPOST,11/12] x86/hvm/ioreq: defer mapping gfns until they are actually requsted

Message ID 20170822145107.6877-12-paul.durrant@citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

Paul Durrant Aug. 22, 2017, 2:51 p.m. UTC
A subsequent patch will introduce a new scheme to allow an emulator to
map IOREQ server pages directly from Xen rather than the guest P2M.

This patch lays the groundwork for that change by deferring mapping of
gfns until their values are requested by an emulator. To that end, the
pad field of the xen_dm_op_get_ioreq_server_info structure is re-purposed
to a flags field and new flag, XEN_DMOP_no_gfns, defined which modifies the
behaviour of XEN_DMOP_get_ioreq_server_info to allow the caller to avoid
requesting the gfn values.

Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
---
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Cc: Wei Liu <wei.liu2@citrix.com>
Cc: Andrew Cooper <andrew.cooper3@citrix.com>
Cc: George Dunlap <George.Dunlap@eu.citrix.com>
Cc: Jan Beulich <jbeulich@suse.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>
Cc: Tim Deegan <tim@xen.org>
---
 tools/libs/devicemodel/core.c                   |  8 +++++
 tools/libs/devicemodel/include/xendevicemodel.h |  6 ++--
 xen/arch/x86/hvm/dm.c                           |  9 +++--
 xen/arch/x86/hvm/ioreq.c                        | 44 ++++++++++++++-----------
 xen/include/asm-x86/hvm/domain.h                |  2 +-
 xen/include/public/hvm/dm_op.h                  | 32 ++++++++++--------
 6 files changed, 61 insertions(+), 40 deletions(-)

Comments

Roger Pau Monné Aug. 24, 2017, 5:21 p.m. UTC | #1
On Tue, Aug 22, 2017 at 03:51:05PM +0100, Paul Durrant wrote:
> A subsequent patch will introduce a new scheme to allow an emulator to
> map IOREQ server pages directly from Xen rather than the guest P2M.
> 
> This patch lays the groundwork for that change by deferring mapping of
> gfns until their values are requested by an emulator. To that end, the
> pad field of the xen_dm_op_get_ioreq_server_info structure is re-purposed
> to a flags field and new flag, XEN_DMOP_no_gfns, defined which modifies the
> behaviour of XEN_DMOP_get_ioreq_server_info to allow the caller to avoid
> requesting the gfn values.
> 
> Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
> ---
> Cc: Ian Jackson <ian.jackson@eu.citrix.com>
> Cc: Wei Liu <wei.liu2@citrix.com>
> Cc: Andrew Cooper <andrew.cooper3@citrix.com>
> Cc: George Dunlap <George.Dunlap@eu.citrix.com>
> Cc: Jan Beulich <jbeulich@suse.com>
> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> Cc: Stefano Stabellini <sstabellini@kernel.org>
> Cc: Tim Deegan <tim@xen.org>
> ---
>  tools/libs/devicemodel/core.c                   |  8 +++++
>  tools/libs/devicemodel/include/xendevicemodel.h |  6 ++--
>  xen/arch/x86/hvm/dm.c                           |  9 +++--
>  xen/arch/x86/hvm/ioreq.c                        | 44 ++++++++++++++-----------
>  xen/include/asm-x86/hvm/domain.h                |  2 +-
>  xen/include/public/hvm/dm_op.h                  | 32 ++++++++++--------
>  6 files changed, 61 insertions(+), 40 deletions(-)
> 
> diff --git a/tools/libs/devicemodel/core.c b/tools/libs/devicemodel/core.c
> index fcb260d29b..907c894e77 100644
> --- a/tools/libs/devicemodel/core.c
> +++ b/tools/libs/devicemodel/core.c
> @@ -188,6 +188,14 @@ int xendevicemodel_get_ioreq_server_info(
>  
>      data->id = id;
>  
> +    /*
> +     * If the caller is not requesting gfn values then instruct the
> +     * hypercall not to retrieve them as this may cause them to be
> +     * mapped.
> +     */
> +    if (!ioreq_gfn && !bufioreq_gfn)
> +        data->flags = XEN_DMOP_no_gfns;

Since this is memset to 0 I would use |= here, in case someone adds a
new flag further up.

Also, seeing the code below, don't you need to retry on error in case
you are dealing with an old hypervisor version? (that will choke on pad
being set).

> diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h
> index 7b93d10209..b8bcd559a5 100644
> --- a/xen/include/asm-x86/hvm/domain.h
> +++ b/xen/include/asm-x86/hvm/domain.h
> @@ -70,7 +70,7 @@ struct hvm_ioreq_server {
>      evtchn_port_t          bufioreq_evtchn;
>      struct rangeset        *range[NR_IO_RANGE_TYPES];

I would place bufioreq_handling here in order to have a more compact
structure layout.

>      bool                   enabled;
> -    bool                   bufioreq_atomic;
> +    int                    bufioreq_handling;
>      bool                   is_default;
>  };
>  
> diff --git a/xen/include/public/hvm/dm_op.h b/xen/include/public/hvm/dm_op.h
> index 6bbab5fca3..9677bd74e7 100644
> --- a/xen/include/public/hvm/dm_op.h
> +++ b/xen/include/public/hvm/dm_op.h
> @@ -79,28 +79,34 @@ struct xen_dm_op_create_ioreq_server {
>   * XEN_DMOP_get_ioreq_server_info: Get all the information necessary to
>   *                                 access IOREQ Server <id>.
>   *
> - * The emulator needs to map the synchronous ioreq structures and buffered
> - * ioreq ring (if it exists) that Xen uses to request emulation. These are
> - * hosted in the target domain's gmfns <ioreq_gfn> and <bufioreq_gfn>
> - * respectively. In addition, if the IOREQ Server is handling buffered
> - * emulation requests, the emulator needs to bind to event channel
> - * <bufioreq_port> to listen for them. (The event channels used for
> - * synchronous emulation requests are specified in the per-CPU ioreq
> - * structures in <ioreq_gfn>).
> - * If the IOREQ Server is not handling buffered emulation requests then the
> - * values handed back in <bufioreq_gfn> and <bufioreq_port> will both be 0.
> + * If the IOREQ Server is handling buffered emulation requests, the
> + * emulator needs to bind to event channel <bufioreq_port> to listen for
> + * them. (The event channels used for synchronous emulation requests are
> + * specified in the per-CPU ioreq structures).
> + * In addition, if the XENMEM_acquire_resource memory op cannot be used,
> + * the emulator will need to map the synchronous ioreq structures and
> + * buffered ioreq ring (if it exists) from guest memory. If <flags> does
> + * not contain XEN_DMOP_no_gfns then these pages will be made available and
> + * the frame numbers passed back in gfns <ioreq_gfn> and <bufioreq_gfn>
> + * respectively. (If the IOREQ Server is not handling buffered emulation
> + * only <ioreq_gfn> will be valid).
>   */
>  #define XEN_DMOP_get_ioreq_server_info 2
>  
>  struct xen_dm_op_get_ioreq_server_info {
>      /* IN - server id */
>      ioservid_t id;
> -    uint16_t pad;
> +    /* IN - flags */
> +    uint16_t flags;

Don't you need to bump some version or similar to let the consumers
know this field is now available? Or that's done using a compile test?

> +#define _XEN_DMOP_no_gfns 0
> +#define XEN_DMOP_no_gfns (1u << _XEN_DMOP_no_gfns)
> +
>      /* OUT - buffered ioreq port */
>      evtchn_port_t bufioreq_port;
> -    /* OUT - sync ioreq gfn */
> +    /* OUT - sync ioreq gfn (see block comment above) */
>      uint64_aligned_t ioreq_gfn;
> -    /* OUT - buffered ioreq gfn */
> +    /* OUT - buffered ioreq gfn (see block comment above)*/
>      uint64_aligned_t bufioreq_gfn;
>  };
>  
> -- 
> 2.11.0
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> https://lists.xen.org/xen-devel
Paul Durrant Aug. 25, 2017, 9:52 a.m. UTC | #2
> -----Original Message-----
> From: Roger Pau Monne
> Sent: 24 August 2017 18:21
> To: Paul Durrant <Paul.Durrant@citrix.com>
> Cc: xen-devel@lists.xenproject.org; Stefano Stabellini
> <sstabellini@kernel.org>; Wei Liu <wei.liu2@citrix.com>; George Dunlap
> <George.Dunlap@citrix.com>; Andrew Cooper
> <Andrew.Cooper3@citrix.com>; Ian Jackson <Ian.Jackson@citrix.com>; Tim
> (Xen.org) <tim@xen.org>; Jan Beulich <jbeulich@suse.com>
> Subject: Re: [Xen-devel] [PATCH v2 REPOST 11/12] x86/hvm/ioreq: defer
> mapping gfns until they are actually requsted
> 
> On Tue, Aug 22, 2017 at 03:51:05PM +0100, Paul Durrant wrote:
> > A subsequent patch will introduce a new scheme to allow an emulator to
> > map IOREQ server pages directly from Xen rather than the guest P2M.
> >
> > This patch lays the groundwork for that change by deferring mapping of
> > gfns until their values are requested by an emulator. To that end, the
> > pad field of the xen_dm_op_get_ioreq_server_info structure is re-
> purposed
> > to a flags field and new flag, XEN_DMOP_no_gfns, defined which modifies
> the
> > behaviour of XEN_DMOP_get_ioreq_server_info to allow the caller to
> avoid
> > requesting the gfn values.
> >
> > Signed-off-by: Paul Durrant <paul.durrant@citrix.com>
> > ---
> > Cc: Ian Jackson <ian.jackson@eu.citrix.com>
> > Cc: Wei Liu <wei.liu2@citrix.com>
> > Cc: Andrew Cooper <andrew.cooper3@citrix.com>
> > Cc: George Dunlap <George.Dunlap@eu.citrix.com>
> > Cc: Jan Beulich <jbeulich@suse.com>
> > Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
> > Cc: Stefano Stabellini <sstabellini@kernel.org>
> > Cc: Tim Deegan <tim@xen.org>
> > ---
> >  tools/libs/devicemodel/core.c                   |  8 +++++
> >  tools/libs/devicemodel/include/xendevicemodel.h |  6 ++--
> >  xen/arch/x86/hvm/dm.c                           |  9 +++--
> >  xen/arch/x86/hvm/ioreq.c                        | 44 ++++++++++++++-----------
> >  xen/include/asm-x86/hvm/domain.h                |  2 +-
> >  xen/include/public/hvm/dm_op.h                  | 32 ++++++++++--------
> >  6 files changed, 61 insertions(+), 40 deletions(-)
> >
> > diff --git a/tools/libs/devicemodel/core.c b/tools/libs/devicemodel/core.c
> > index fcb260d29b..907c894e77 100644
> > --- a/tools/libs/devicemodel/core.c
> > +++ b/tools/libs/devicemodel/core.c
> > @@ -188,6 +188,14 @@ int xendevicemodel_get_ioreq_server_info(
> >
> >      data->id = id;
> >
> > +    /*
> > +     * If the caller is not requesting gfn values then instruct the
> > +     * hypercall not to retrieve them as this may cause them to be
> > +     * mapped.
> > +     */
> > +    if (!ioreq_gfn && !bufioreq_gfn)
> > +        data->flags = XEN_DMOP_no_gfns;
> 
> Since this is memset to 0 I would use |= here, in case someone adds a
> new flag further up.

Ok.

> 
> Also, seeing the code below, don't you need to retry on error in case
> you are dealing with an old hypervisor version? (that will choke on pad
> being set).
>

This is tools code so there should be no possibility of a mismatch with the hypervisor.
 
> > diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-
> x86/hvm/domain.h
> > index 7b93d10209..b8bcd559a5 100644
> > --- a/xen/include/asm-x86/hvm/domain.h
> > +++ b/xen/include/asm-x86/hvm/domain.h
> > @@ -70,7 +70,7 @@ struct hvm_ioreq_server {
> >      evtchn_port_t          bufioreq_evtchn;
> >      struct rangeset        *range[NR_IO_RANGE_TYPES];
> 
> I would place bufioreq_handling here in order to have a more compact
> structure layout.

Ok.

> 
> >      bool                   enabled;
> > -    bool                   bufioreq_atomic;
> > +    int                    bufioreq_handling;
> >      bool                   is_default;
> >  };
> >
> > diff --git a/xen/include/public/hvm/dm_op.h
> b/xen/include/public/hvm/dm_op.h
> > index 6bbab5fca3..9677bd74e7 100644
> > --- a/xen/include/public/hvm/dm_op.h
> > +++ b/xen/include/public/hvm/dm_op.h
> > @@ -79,28 +79,34 @@ struct xen_dm_op_create_ioreq_server {
> >   * XEN_DMOP_get_ioreq_server_info: Get all the information necessary
> to
> >   *                                 access IOREQ Server <id>.
> >   *
> > - * The emulator needs to map the synchronous ioreq structures and
> buffered
> > - * ioreq ring (if it exists) that Xen uses to request emulation. These are
> > - * hosted in the target domain's gmfns <ioreq_gfn> and <bufioreq_gfn>
> > - * respectively. In addition, if the IOREQ Server is handling buffered
> > - * emulation requests, the emulator needs to bind to event channel
> > - * <bufioreq_port> to listen for them. (The event channels used for
> > - * synchronous emulation requests are specified in the per-CPU ioreq
> > - * structures in <ioreq_gfn>).
> > - * If the IOREQ Server is not handling buffered emulation requests then
> the
> > - * values handed back in <bufioreq_gfn> and <bufioreq_port> will both be
> 0.
> > + * If the IOREQ Server is handling buffered emulation requests, the
> > + * emulator needs to bind to event channel <bufioreq_port> to listen for
> > + * them. (The event channels used for synchronous emulation requests
> are
> > + * specified in the per-CPU ioreq structures).
> > + * In addition, if the XENMEM_acquire_resource memory op cannot be
> used,
> > + * the emulator will need to map the synchronous ioreq structures and
> > + * buffered ioreq ring (if it exists) from guest memory. If <flags> does
> > + * not contain XEN_DMOP_no_gfns then these pages will be made
> available and
> > + * the frame numbers passed back in gfns <ioreq_gfn> and
> <bufioreq_gfn>
> > + * respectively. (If the IOREQ Server is not handling buffered emulation
> > + * only <ioreq_gfn> will be valid).
> >   */
> >  #define XEN_DMOP_get_ioreq_server_info 2
> >
> >  struct xen_dm_op_get_ioreq_server_info {
> >      /* IN - server id */
> >      ioservid_t id;
> > -    uint16_t pad;
> > +    /* IN - flags */
> > +    uint16_t flags;
> 
> Don't you need to bump some version or similar to let the consumers
> know this field is now available? Or that's done using a compile test?
> 

No. Again this is tools code so the caller should maintain compat based on the version of Xen.

Cheers,

  Paul

> > +#define _XEN_DMOP_no_gfns 0
> > +#define XEN_DMOP_no_gfns (1u << _XEN_DMOP_no_gfns)
> > +
> >      /* OUT - buffered ioreq port */
> >      evtchn_port_t bufioreq_port;
> > -    /* OUT - sync ioreq gfn */
> > +    /* OUT - sync ioreq gfn (see block comment above) */
> >      uint64_aligned_t ioreq_gfn;
> > -    /* OUT - buffered ioreq gfn */
> > +    /* OUT - buffered ioreq gfn (see block comment above)*/
> >      uint64_aligned_t bufioreq_gfn;
> >  };
> >
> > --
> > 2.11.0
> >
> >
> > _______________________________________________
> > Xen-devel mailing list
> > Xen-devel@lists.xen.org
> > https://lists.xen.org/xen-devel
Wei Liu Aug. 28, 2017, 3:08 p.m. UTC | #3
On Tue, Aug 22, 2017 at 03:51:05PM +0100, Paul Durrant wrote:
[...]
> diff --git a/tools/libs/devicemodel/include/xendevicemodel.h b/tools/libs/devicemodel/include/xendevicemodel.h
> index 13216db04a..da6b253cfd 100644
> --- a/tools/libs/devicemodel/include/xendevicemodel.h
> +++ b/tools/libs/devicemodel/include/xendevicemodel.h
> @@ -61,11 +61,11 @@ int xendevicemodel_create_ioreq_server(
>   * @parm domid the domain id to be serviced
>   * @parm id the IOREQ Server id.
>   * @parm ioreq_gfn pointer to a xen_pfn_t to receive the synchronous ioreq
> - *                  gfn
> + *                  gmfn. (May be NULL if not required)
>   * @parm bufioreq_gfn pointer to a xen_pfn_t to receive the buffered ioreq
> - *                    gfn
> + *                    gmfn. (May be NULL if not required)

Should be gfn here.
Paul Durrant Aug. 29, 2017, 8:51 a.m. UTC | #4
> -----Original Message-----
> From: Wei Liu [mailto:wei.liu2@citrix.com]
> Sent: 28 August 2017 16:09
> To: Paul Durrant <Paul.Durrant@citrix.com>
> Cc: xen-devel@lists.xenproject.org; Ian Jackson <Ian.Jackson@citrix.com>;
> Wei Liu <wei.liu2@citrix.com>; Andrew Cooper
> <Andrew.Cooper3@citrix.com>; George Dunlap
> <George.Dunlap@citrix.com>; Jan Beulich <jbeulich@suse.com>; Konrad
> Rzeszutek Wilk <konrad.wilk@oracle.com>; Stefano Stabellini
> <sstabellini@kernel.org>; Tim (Xen.org) <tim@xen.org>
> Subject: Re: [PATCH v2 REPOST 11/12] x86/hvm/ioreq: defer mapping gfns
> until they are actually requsted
> 
> On Tue, Aug 22, 2017 at 03:51:05PM +0100, Paul Durrant wrote:
> [...]
> > diff --git a/tools/libs/devicemodel/include/xendevicemodel.h
> b/tools/libs/devicemodel/include/xendevicemodel.h
> > index 13216db04a..da6b253cfd 100644
> > --- a/tools/libs/devicemodel/include/xendevicemodel.h
> > +++ b/tools/libs/devicemodel/include/xendevicemodel.h
> > @@ -61,11 +61,11 @@ int xendevicemodel_create_ioreq_server(
> >   * @parm domid the domain id to be serviced
> >   * @parm id the IOREQ Server id.
> >   * @parm ioreq_gfn pointer to a xen_pfn_t to receive the synchronous
> ioreq
> > - *                  gfn
> > + *                  gmfn. (May be NULL if not required)
> >   * @parm bufioreq_gfn pointer to a xen_pfn_t to receive the buffered
> ioreq
> > - *                    gfn
> > + *                    gmfn. (May be NULL if not required)
> 
> Should be gfn here.

Actually, yes. It will still be always gfn for the legacy call.
diff mbox

Patch

diff --git a/tools/libs/devicemodel/core.c b/tools/libs/devicemodel/core.c
index fcb260d29b..907c894e77 100644
--- a/tools/libs/devicemodel/core.c
+++ b/tools/libs/devicemodel/core.c
@@ -188,6 +188,14 @@  int xendevicemodel_get_ioreq_server_info(
 
     data->id = id;
 
+    /*
+     * If the caller is not requesting gfn values then instruct the
+     * hypercall not to retrieve them as this may cause them to be
+     * mapped.
+     */
+    if (!ioreq_gfn && !bufioreq_gfn)
+        data->flags = XEN_DMOP_no_gfns;
+
     rc = xendevicemodel_op(dmod, domid, 1, &op, sizeof(op));
     if (rc)
         return rc;
diff --git a/tools/libs/devicemodel/include/xendevicemodel.h b/tools/libs/devicemodel/include/xendevicemodel.h
index 13216db04a..da6b253cfd 100644
--- a/tools/libs/devicemodel/include/xendevicemodel.h
+++ b/tools/libs/devicemodel/include/xendevicemodel.h
@@ -61,11 +61,11 @@  int xendevicemodel_create_ioreq_server(
  * @parm domid the domain id to be serviced
  * @parm id the IOREQ Server id.
  * @parm ioreq_gfn pointer to a xen_pfn_t to receive the synchronous ioreq
- *                  gfn
+ *                  gmfn. (May be NULL if not required)
  * @parm bufioreq_gfn pointer to a xen_pfn_t to receive the buffered ioreq
- *                    gfn
+ *                    gmfn. (May be NULL if not required)
  * @parm bufioreq_port pointer to a evtchn_port_t to receive the buffered
- *                     ioreq event channel
+ *                     ioreq event channel. (May be NULL if not required)
  * @return 0 on success, -1 on failure.
  */
 int xendevicemodel_get_ioreq_server_info(
diff --git a/xen/arch/x86/hvm/dm.c b/xen/arch/x86/hvm/dm.c
index 87ef4b6ca9..c020f0c99f 100644
--- a/xen/arch/x86/hvm/dm.c
+++ b/xen/arch/x86/hvm/dm.c
@@ -418,16 +418,19 @@  static int dm_op(const struct dmop_args *op_args)
     {
         struct xen_dm_op_get_ioreq_server_info *data =
             &op.u.get_ioreq_server_info;
+        const uint16_t valid_flags = XEN_DMOP_no_gfns;
 
         const_op = false;
 
         rc = -EINVAL;
-        if ( data->pad )
+        if ( data->flags & ~valid_flags )
             break;
 
         rc = hvm_get_ioreq_server_info(d, data->id,
-                                       &data->ioreq_gfn,
-                                       &data->bufioreq_gfn,
+                                       (data->flags & XEN_DMOP_no_gfns) ?
+                                       NULL : &data->ioreq_gfn,
+                                       (data->flags & XEN_DMOP_no_gfns) ?
+                                       NULL : &data->bufioreq_gfn,
                                        &data->bufioreq_port);
         break;
     }
diff --git a/xen/arch/x86/hvm/ioreq.c b/xen/arch/x86/hvm/ioreq.c
index 3a9aaf1f5d..795c198f95 100644
--- a/xen/arch/x86/hvm/ioreq.c
+++ b/xen/arch/x86/hvm/ioreq.c
@@ -344,7 +344,8 @@  static int hvm_ioreq_server_add_vcpu(struct hvm_ioreq_server *s,
 
     sv->ioreq_evtchn = rc;
 
-    if ( v->vcpu_id == 0 && s->bufioreq.va != NULL )
+    if ( v->vcpu_id == 0 &&
+         (s->bufioreq_handling != HVM_IOREQSRV_BUFIOREQ_OFF) )
     {
         struct domain *d = s->domain;
 
@@ -395,7 +396,8 @@  static void hvm_ioreq_server_remove_vcpu(struct hvm_ioreq_server *s,
 
         list_del(&sv->list_entry);
 
-        if ( v->vcpu_id == 0 && s->bufioreq.va != NULL )
+        if ( v->vcpu_id == 0 &&
+             (s->bufioreq_handling != HVM_IOREQSRV_BUFIOREQ_OFF) )
             free_xen_event_channel(v->domain, s->bufioreq_evtchn);
 
         free_xen_event_channel(v->domain, sv->ioreq_evtchn);
@@ -422,7 +424,8 @@  static void hvm_ioreq_server_remove_all_vcpus(struct hvm_ioreq_server *s)
 
         list_del(&sv->list_entry);
 
-        if ( v->vcpu_id == 0 && s->bufioreq.va != NULL )
+        if ( v->vcpu_id == 0 &&
+             (s->bufioreq_handling != HVM_IOREQSRV_BUFIOREQ_OFF) )
             free_xen_event_channel(v->domain, s->bufioreq_evtchn);
 
         free_xen_event_channel(v->domain, sv->ioreq_evtchn);
@@ -433,14 +436,13 @@  static void hvm_ioreq_server_remove_all_vcpus(struct hvm_ioreq_server *s)
     spin_unlock(&s->lock);
 }
 
-static int hvm_ioreq_server_map_pages(struct hvm_ioreq_server *s,
-                                      bool handle_bufioreq)
+static int hvm_ioreq_server_map_pages(struct hvm_ioreq_server *s)
 {
     int rc = -ENOMEM;
 
     rc = hvm_map_ioreq_gfn(s, false);
 
-    if ( !rc && handle_bufioreq )
+    if ( !rc && (s->bufioreq_handling != HVM_IOREQSRV_BUFIOREQ_OFF) )
         rc = hvm_map_ioreq_gfn(s, true);
 
     if ( rc )
@@ -568,13 +570,7 @@  static int hvm_ioreq_server_init(struct hvm_ioreq_server *s,
     if ( rc )
         return rc;
 
-    if ( bufioreq_handling == HVM_IOREQSRV_BUFIOREQ_ATOMIC )
-        s->bufioreq_atomic = true;
-
-    rc = hvm_ioreq_server_map_pages(
-             s, bufioreq_handling != HVM_IOREQSRV_BUFIOREQ_OFF);
-    if ( rc )
-        goto fail_map;
+    s->bufioreq_handling = bufioreq_handling;
 
     for_each_vcpu ( d, v )
     {
@@ -589,9 +585,6 @@  static int hvm_ioreq_server_init(struct hvm_ioreq_server *s,
     hvm_ioreq_server_remove_all_vcpus(s);
     hvm_ioreq_server_unmap_pages(s);
 
- fail_map:
-    hvm_ioreq_server_free_rangesets(s);
-
     return rc;
 }
 
@@ -747,11 +740,21 @@  int hvm_get_ioreq_server_info(struct domain *d, ioservid_t id,
         if ( s->id != id )
             continue;
 
-        *ioreq_gfn = gfn_x(s->ioreq.gfn);
+        if ( ioreq_gfn || bufioreq_gfn )
+        {
+            rc = hvm_ioreq_server_map_pages(s);
+            if ( rc )
+                break;
+        }
+
+        if ( ioreq_gfn )
+            *ioreq_gfn = gfn_x(s->ioreq.gfn);
 
-        if ( s->bufioreq.va != NULL )
+        if ( s->bufioreq_handling != HVM_IOREQSRV_BUFIOREQ_OFF )
         {
-            *bufioreq_gfn = gfn_x(s->bufioreq.gfn);
+            if ( bufioreq_gfn )
+                *bufioreq_gfn = gfn_x(s->bufioreq.gfn);
+
             *bufioreq_port = s->bufioreq_evtchn;
         }
 
@@ -1278,7 +1281,8 @@  static int hvm_send_buffered_ioreq(struct hvm_ioreq_server *s, ioreq_t *p)
     pg->ptrs.write_pointer += qw ? 2 : 1;
 
     /* Canonicalize read/write pointers to prevent their overflow. */
-    while ( s->bufioreq_atomic && qw++ < IOREQ_BUFFER_SLOT_NUM &&
+    while ( (s->bufioreq_handling == HVM_IOREQSRV_BUFIOREQ_ATOMIC) &&
+            qw++ < IOREQ_BUFFER_SLOT_NUM &&
             pg->ptrs.read_pointer >= IOREQ_BUFFER_SLOT_NUM )
     {
         union bufioreq_pointers old = pg->ptrs, new;
diff --git a/xen/include/asm-x86/hvm/domain.h b/xen/include/asm-x86/hvm/domain.h
index 7b93d10209..b8bcd559a5 100644
--- a/xen/include/asm-x86/hvm/domain.h
+++ b/xen/include/asm-x86/hvm/domain.h
@@ -70,7 +70,7 @@  struct hvm_ioreq_server {
     evtchn_port_t          bufioreq_evtchn;
     struct rangeset        *range[NR_IO_RANGE_TYPES];
     bool                   enabled;
-    bool                   bufioreq_atomic;
+    int                    bufioreq_handling;
     bool                   is_default;
 };
 
diff --git a/xen/include/public/hvm/dm_op.h b/xen/include/public/hvm/dm_op.h
index 6bbab5fca3..9677bd74e7 100644
--- a/xen/include/public/hvm/dm_op.h
+++ b/xen/include/public/hvm/dm_op.h
@@ -79,28 +79,34 @@  struct xen_dm_op_create_ioreq_server {
  * XEN_DMOP_get_ioreq_server_info: Get all the information necessary to
  *                                 access IOREQ Server <id>.
  *
- * The emulator needs to map the synchronous ioreq structures and buffered
- * ioreq ring (if it exists) that Xen uses to request emulation. These are
- * hosted in the target domain's gmfns <ioreq_gfn> and <bufioreq_gfn>
- * respectively. In addition, if the IOREQ Server is handling buffered
- * emulation requests, the emulator needs to bind to event channel
- * <bufioreq_port> to listen for them. (The event channels used for
- * synchronous emulation requests are specified in the per-CPU ioreq
- * structures in <ioreq_gfn>).
- * If the IOREQ Server is not handling buffered emulation requests then the
- * values handed back in <bufioreq_gfn> and <bufioreq_port> will both be 0.
+ * If the IOREQ Server is handling buffered emulation requests, the
+ * emulator needs to bind to event channel <bufioreq_port> to listen for
+ * them. (The event channels used for synchronous emulation requests are
+ * specified in the per-CPU ioreq structures).
+ * In addition, if the XENMEM_acquire_resource memory op cannot be used,
+ * the emulator will need to map the synchronous ioreq structures and
+ * buffered ioreq ring (if it exists) from guest memory. If <flags> does
+ * not contain XEN_DMOP_no_gfns then these pages will be made available and
+ * the frame numbers passed back in gfns <ioreq_gfn> and <bufioreq_gfn>
+ * respectively. (If the IOREQ Server is not handling buffered emulation
+ * only <ioreq_gfn> will be valid).
  */
 #define XEN_DMOP_get_ioreq_server_info 2
 
 struct xen_dm_op_get_ioreq_server_info {
     /* IN - server id */
     ioservid_t id;
-    uint16_t pad;
+    /* IN - flags */
+    uint16_t flags;
+
+#define _XEN_DMOP_no_gfns 0
+#define XEN_DMOP_no_gfns (1u << _XEN_DMOP_no_gfns)
+
     /* OUT - buffered ioreq port */
     evtchn_port_t bufioreq_port;
-    /* OUT - sync ioreq gfn */
+    /* OUT - sync ioreq gfn (see block comment above) */
     uint64_aligned_t ioreq_gfn;
-    /* OUT - buffered ioreq gfn */
+    /* OUT - buffered ioreq gfn (see block comment above)*/
     uint64_aligned_t bufioreq_gfn;
 };