diff mbox

[v2,1/3] libxl: add PV display device driver interface

Message ID 1495714651-2676-2-git-send-email-al1img@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Oleksandr Grytsov May 25, 2017, 12:17 p.m. UTC
From: Oleksandr Grytsov <oleksandr_grytsov@epam.com>

Signed-off-by: Oleksandr Grytsov <oleksandr_grytsov@epam.com>
---
 tools/libxl/Makefile                 |   2 +-
 tools/libxl/libxl.h                  |  21 ++
 tools/libxl/libxl_create.c           |   3 +
 tools/libxl/libxl_device.c           | 178 ++++++++++++++++-
 tools/libxl/libxl_internal.h         |  24 +++
 tools/libxl/libxl_types.idl          |  40 +++-
 tools/libxl/libxl_types_internal.idl |   1 +
 tools/libxl/libxl_usb.c              |   2 +
 tools/libxl/libxl_utils.h            |   4 +
 tools/libxl/libxl_vdispl.c           | 372 +++++++++++++++++++++++++++++++++++
 10 files changed, 643 insertions(+), 4 deletions(-)
 create mode 100644 tools/libxl/libxl_vdispl.c

Comments

Wei Liu June 20, 2017, 1:54 p.m. UTC | #1
On Thu, May 25, 2017 at 03:17:29PM +0300, Oleksandr Grytsov wrote:
> From: Oleksandr Grytsov <oleksandr_grytsov@epam.com>
> 

I'm sorry, patch like this is impossible to review because: 1. there is
no commit message 2. it is huge.

I can see it is adding a lot of hooks to the device handling framework.
Please explain why they are needed. This sort of changes (refactoring
and extending existing code) should also be in separate patches.

> Signed-off-by: Oleksandr Grytsov <oleksandr_grytsov@epam.com>
> ---
>  tools/libxl/Makefile                 |   2 +-
>  tools/libxl/libxl.h                  |  21 ++
>  tools/libxl/libxl_create.c           |   3 +
>  tools/libxl/libxl_device.c           | 178 ++++++++++++++++-
>  tools/libxl/libxl_internal.h         |  24 +++
>  tools/libxl/libxl_types.idl          |  40 +++-
>  tools/libxl/libxl_types_internal.idl |   1 +
>  tools/libxl/libxl_usb.c              |   2 +
>  tools/libxl/libxl_utils.h            |   4 +
>  tools/libxl/libxl_vdispl.c           | 372 +++++++++++++++++++++++++++++++++++
>  10 files changed, 643 insertions(+), 4 deletions(-)
>  create mode 100644 tools/libxl/libxl_vdispl.c
>  };
>  
> diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
> index 5e96676..2954800 100644
> --- a/tools/libxl/libxl_device.c
> +++ b/tools/libxl/libxl_device.c
> @@ -18,7 +18,7 @@
>  
>  #include "libxl_internal.h"
>  
> -static char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device)
> +char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device)
>  {
>      char *dom_path = libxl__xs_get_dompath(gc, device->domid);
>  
> @@ -1776,6 +1776,182 @@ out:
>      return AO_CREATE_FAIL(rc);
>  }
>  
> +static int device_add_domain_config(libxl__gc *gc, uint32_t domid,
> +                                    const struct libxl_device_type *dt,
> +                                    void *type)
[...]
> +
> +void libxl__device_add(libxl__egc *egc, uint32_t domid,
> +                       const struct libxl_device_type *dt, void *type,
> +                       libxl__ao_device *aodev)
[...]
> +
> +void* libxl__device_list(const struct libxl_device_type *dt,
> +                         libxl_ctx *ctx, uint32_t domid, int *num)
[...]
> +
> +void libxl__device_list_free(const struct libxl_device_type *dt,
> +                             void *list, int num)
> 

I think existing code already provides these functionalities, right?
Oleksandr Grytsov June 21, 2017, 10:11 a.m. UTC | #2
On Tue, Jun 20, 2017 at 4:54 PM, Wei Liu <wei.liu2@citrix.com> wrote:
> On Thu, May 25, 2017 at 03:17:29PM +0300, Oleksandr Grytsov wrote:
>> From: Oleksandr Grytsov <oleksandr_grytsov@epam.com>
>>

Hi Wei,

Thank you for your reply.

> I'm sorry, patch like this is impossible to review because: 1. there is
> no commit message 2. it is huge.

I will separate it to small ones and will add commit message.

> I can see it is adding a lot of hooks to the device handling framework.
> Please explain why they are needed. This sort of changes (refactoring
> and extending existing code) should also be in separate patches.

Hooks in the device handling framework is needed to avoid code duplication
on new PV device adding. There were two possibilities either use macro
or extend the device handling framework. See [1] and following conversation
for more details. The patches don't refactor existing code they extend
hooks to the device handling framework and add new functionality required
to add the display device driver.

Almost all libxl__device_xxxx_add functions are the same except Xen store
parameters. So, I've moved setting Xen store parameters  to
set_xenstore_config hook
and have created common function to add device (add hook).
Also I've created functions to libxl_device_xxxx_list and
libxl_device_xxxx_list_free.
which take device type as parameter.

>
>> Signed-off-by: Oleksandr Grytsov <oleksandr_grytsov@epam.com>
>> ---
>>  tools/libxl/Makefile                 |   2 +-
>>  tools/libxl/libxl.h                  |  21 ++
>>  tools/libxl/libxl_create.c           |   3 +
>>  tools/libxl/libxl_device.c           | 178 ++++++++++++++++-
>>  tools/libxl/libxl_internal.h         |  24 +++
>>  tools/libxl/libxl_types.idl          |  40 +++-
>>  tools/libxl/libxl_types_internal.idl |   1 +
>>  tools/libxl/libxl_usb.c              |   2 +
>>  tools/libxl/libxl_utils.h            |   4 +
>>  tools/libxl/libxl_vdispl.c           | 372 +++++++++++++++++++++++++++++++++++
>>  10 files changed, 643 insertions(+), 4 deletions(-)
>>  create mode 100644 tools/libxl/libxl_vdispl.c
>>  };
>>
>> diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
>> index 5e96676..2954800 100644
>> --- a/tools/libxl/libxl_device.c
>> +++ b/tools/libxl/libxl_device.c
>> @@ -18,7 +18,7 @@
>>
>>  #include "libxl_internal.h"
>>
>> -static char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device)
>> +char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device)
>>  {
>>      char *dom_path = libxl__xs_get_dompath(gc, device->domid);
>>
>> @@ -1776,6 +1776,182 @@ out:
>>      return AO_CREATE_FAIL(rc);
>>  }
>>
>> +static int device_add_domain_config(libxl__gc *gc, uint32_t domid,
>> +                                    const struct libxl_device_type *dt,
>> +                                    void *type)
> [...]
>> +
>> +void libxl__device_add(libxl__egc *egc, uint32_t domid,
>> +                       const struct libxl_device_type *dt, void *type,
>> +                       libxl__ao_device *aodev)
> [...]
>> +
>> +void* libxl__device_list(const struct libxl_device_type *dt,
>> +                         libxl_ctx *ctx, uint32_t domid, int *num)
> [...]
>> +
>> +void libxl__device_list_free(const struct libxl_device_type *dt,
>> +                             void *list, int num)
>>
>
> I think existing code already provides these functionalities, right?

Right, but as I mentioned before there are almost same functions for
each device. These new functions are generic.

[1] http://marc.info/?l=xen-devel&m=149026463411873&w=2
diff mbox

Patch

diff --git a/tools/libxl/Makefile b/tools/libxl/Makefile
index 566b706..3a932e1 100644
--- a/tools/libxl/Makefile
+++ b/tools/libxl/Makefile
@@ -138,7 +138,7 @@  LIBXL_OBJS = flexarray.o libxl.o libxl_create.o libxl_dm.o libxl_pci.o \
 			libxl_dom_suspend.o libxl_dom_save.o libxl_usb.o \
 			libxl_vtpm.o libxl_nic.o libxl_disk.o libxl_console.o \
 			libxl_cpupool.o libxl_mem.o libxl_sched.o libxl_tmem.o \
-			libxl_domain.o \
+			libxl_domain.o libxl_vdispl.o \
                         $(LIBXL_OBJS-y)
 LIBXL_OBJS += libxl_genid.o
 LIBXL_OBJS += _libxl_types.o libxl_flask.o _libxl_types_internal.o
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index 72ec39d..4eff121 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -1833,6 +1833,27 @@  libxl_device_vtpm *libxl_device_vtpm_list(libxl_ctx *ctx, uint32_t domid, int *n
 int libxl_device_vtpm_getinfo(libxl_ctx *ctx, uint32_t domid,
                                libxl_device_vtpm *vtpm, libxl_vtpminfo *vtpminfo);
 
+/* Virtual displays */
+int libxl_device_vdispl_add(libxl_ctx *ctx, uint32_t domid,
+                            libxl_device_vdispl *displ,
+                            const libxl_asyncop_how *ao_how)
+                            LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_device_vdispl_remove(libxl_ctx *ctx, uint32_t domid,
+                               libxl_device_vdispl *vdispl,
+                               const libxl_asyncop_how *ao_how)
+                               LIBXL_EXTERNAL_CALLERS_ONLY;
+int libxl_device_vdispl_destroy(libxl_ctx *ctx, uint32_t domid,
+                                libxl_device_vdispl *vdispl,
+                                const libxl_asyncop_how *ao_how)
+                                LIBXL_EXTERNAL_CALLERS_ONLY;
+
+libxl_device_vdispl *libxl_device_vdispl_list(libxl_ctx *ctx, uint32_t domid,
+                                              int *num);
+void libxl_device_vdispl_list_free(libxl_device_vdispl* list, int num);
+int libxl_device_vdispl_getinfo(libxl_ctx *ctx, uint32_t domid,
+                                libxl_device_vdispl *vdispl,
+                                libxl_vdisplinfo *vdisplinfo);
+
 /* Keyboard */
 int libxl_device_vkb_add(libxl_ctx *ctx, uint32_t domid, libxl_device_vkb *vkb,
                          const libxl_asyncop_how *ao_how)
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 25389e1..b36383f 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -1422,6 +1422,8 @@  out:
 
 #define libxl_device_dtdev_list NULL
 #define libxl_device_dtdev_compare NULL
+#define libxl__device_from_dtdev NULL
+#define libxl__device_dtdev_setdefault NULL
 static DEFINE_DEVICE_TYPE_STRUCT(dtdev);
 
 const struct libxl_device_type *device_type_tbl[] = {
@@ -1432,6 +1434,7 @@  const struct libxl_device_type *device_type_tbl[] = {
     &libxl__usbdev_devtype,
     &libxl__pcidev_devtype,
     &libxl__dtdev_devtype,
+    &libxl__vdispl_devtype,
     NULL
 };
 
diff --git a/tools/libxl/libxl_device.c b/tools/libxl/libxl_device.c
index 5e96676..2954800 100644
--- a/tools/libxl/libxl_device.c
+++ b/tools/libxl/libxl_device.c
@@ -18,7 +18,7 @@ 
 
 #include "libxl_internal.h"
 
-static char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device)
+char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device)
 {
     char *dom_path = libxl__xs_get_dompath(gc, device->domid);
 
@@ -1776,6 +1776,182 @@  out:
     return AO_CREATE_FAIL(rc);
 }
 
+static int device_add_domain_config(libxl__gc *gc, uint32_t domid,
+                                    const struct libxl_device_type *dt,
+                                    void *type)
+{
+    int rc;
+    libxl_domain_config d_config;
+    libxl__domain_userdata_lock *lock = NULL;
+    int *num_dev;
+    int i;
+    void *item = NULL;
+
+    libxl_domain_config_init(&d_config);
+
+    lock = libxl__lock_domain_userdata(gc, domid);
+    if (!lock) {
+        rc = ERROR_LOCK_FAIL; goto out;
+    }
+
+    rc = libxl__get_domain_configuration(gc, domid, &d_config);
+    if (rc) goto out;
+
+    num_dev = libxl__device_type_get_num(dt, &d_config);
+
+    /* Check for existing device */
+    for (i = 0; i < *num_dev; i++) {
+        if (dt->compare(libxl__device_type_get_elem(dt, &d_config, i), type)) {
+            item = libxl__device_type_get_elem(dt, &d_config, i);
+        }
+    }
+
+    if (!item) {
+        void **devs= libxl__device_type_get_ptr(dt, &d_config);
+        *devs = libxl__realloc(NOGC, *devs,
+                               dt->dev_elem_size * (*num_dev + 1));
+        item = libxl__device_type_get_elem(dt, &d_config, *num_dev);
+        (*num_dev)++;
+    } else {
+        dt->dispose(item);
+    }
+
+    dt->init(item);
+    dt->copy(CTX, item, type);
+
+    rc = libxl__dm_check_start(gc, &d_config, domid);
+    if (rc) goto out;
+
+    rc = libxl__set_domain_configuration(gc, domid, &d_config);
+    if (rc) goto out;
+
+    rc = 0;
+
+out:
+    if (lock) libxl__unlock_domain_userdata(lock);
+    libxl_domain_config_dispose(&d_config);
+    return rc;
+}
+
+void libxl__device_add(libxl__egc *egc, uint32_t domid,
+                       const struct libxl_device_type *dt, void *type,
+                       libxl__ao_device *aodev)
+{
+    STATE_AO_GC(aodev->ao);
+    libxl__device *device;
+    int rc;
+
+    rc = dt->set_default(gc, domid, type);
+    if (rc) goto out;
+
+    GCNEW(device);
+    rc = dt->to_device(gc, domid, type, device);
+    if ( rc != 0 ) goto out;
+
+    rc = libxl__device_exists(gc, XBT_NULL, device);
+    if (rc < 0) goto out;
+    if (rc == 1) {              /* already exists in xenstore */
+        LOGD(ERROR, domid, "device already exists in xenstore");
+        aodev->action = LIBXL__DEVICE_ACTION_ADD; /* for error message */
+        rc = ERROR_DEVICE_EXISTS;
+        goto out;
+    }
+
+    if (aodev->update_json) {
+        rc = device_add_domain_config(gc, domid, dt, type);
+        if (rc) goto out;
+    }
+
+    if (dt->set_xenstore_config) {
+        rc = dt->set_xenstore_config(gc, domid, type);
+        if (rc) goto out;
+    }
+
+    aodev->dev = device;
+    aodev->action = LIBXL__DEVICE_ACTION_ADD;
+    libxl__wait_device_connection(egc, aodev);
+
+    rc = 0;
+
+out:
+    aodev->rc = rc;
+    if(rc) aodev->callback(egc, aodev);
+    return;
+}
+
+void* libxl__device_list(const struct libxl_device_type *dt,
+                         libxl_ctx *ctx, uint32_t domid, int *num)
+{
+    GC_INIT(ctx);
+
+    void *r = NULL;
+    void *list = NULL;
+    void *item = NULL;
+    char *libxl_path;
+    char *be_path;
+    char** dir = NULL;
+    unsigned int ndirs = 0;
+    int rc;
+
+    *num = 0;
+
+    libxl_path = GCSPRINTF("%s/device/%s",
+                           libxl__xs_libxl_path(gc, domid), dt->type);
+
+    dir = libxl__xs_directory(gc, XBT_NULL, libxl_path, &ndirs);
+
+    if (dir && ndirs) {
+        list = malloc(dt->dev_elem_size * ndirs);
+        void *end = (uint8_t*)list + ndirs * dt->dev_elem_size;
+        item = list;
+
+        while(item < end) {
+            be_path = libxl__xs_read(gc, XBT_NULL,
+                                     GCSPRINTF("%s/%s/backend",
+                                     libxl_path, *dir));
+
+            dt->init(item);
+
+            rc = dt->from_xenstore(gc, be_path, atoi(*dir), item);
+            if (rc) goto out;
+
+            item = (uint8_t*)item + dt->dev_elem_size;
+            ++dir;
+        }
+    }
+
+    *num = ndirs;
+    r = list;
+    list = NULL;
+
+out:
+
+    if (list) {
+        *num = 0;
+        while(item >= list) {
+            item = (uint8_t*)item - dt->dev_elem_size;
+            dt->dispose(item);
+        }
+        free(list);
+    }
+
+    GC_FREE;
+
+    return r;
+}
+
+void libxl__device_list_free(const struct libxl_device_type *dt,
+                             void *list, int num)
+{
+    int i;
+
+    for (i = 0; i < num; i++) {
+        dt->dispose((uint8_t*)list + i * dt->dev_elem_size);
+    }
+
+    free(list);
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 25cb08a..9e51823 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1204,6 +1204,7 @@  _hidden int libxl__device_exists(libxl__gc *gc, xs_transaction_t t,
                                  libxl__device *device);
 _hidden int libxl__device_generic_add(libxl__gc *gc, xs_transaction_t t,
         libxl__device *device, char **bents, char **fents, char **ro_fents);
+_hidden char *libxl__device_frontend_path(libxl__gc *gc, libxl__device *device);
 _hidden char *libxl__device_backend_path(libxl__gc *gc, libxl__device *device);
 _hidden char *libxl__device_libxl_path(libxl__gc *gc, libxl__device *device);
 _hidden int libxl__parse_backend_path(libxl__gc *gc, const char *path,
@@ -3473,11 +3474,17 @@  struct libxl_device_type {
     void (*add)(libxl__egc *, libxl__ao *, uint32_t, libxl_domain_config *,
                 libxl__multidev *);
     void *(*list)(libxl_ctx *, uint32_t, int *);
+    int (*set_default)(libxl__gc *, uint32_t, void *);
+    int (*to_device)(libxl__gc *, uint32_t, void *, libxl__device *);
+    void (*init)(void *);
+    void (*copy)(libxl_ctx *, void *, void *);
     void (*dispose)(void *);
     int (*compare)(void *, void *);
     void (*merge)(libxl_ctx *, void *, void *);
     int (*dm_needed)(void *, unsigned);
     void (*update_config)(libxl__gc *, void *, void *);
+    int (*from_xenstore)(libxl__gc *, const char *, uint32_t, void *);
+    int (*set_xenstore_config)(libxl__gc *, uint32_t, void *);
 };
 
 #define DEFINE_DEVICE_TYPE_STRUCT_X(name, sname, ...)                          \
@@ -3489,6 +3496,14 @@  struct libxl_device_type {
         .add           = libxl__add_ ## name ## s,                             \
         .list          = (void *(*)(libxl_ctx *, uint32_t, int *))             \
                          libxl_device_ ## sname ## _list,                      \
+        .set_default   = (int (*)(libxl__gc *, uint32_t, void *))              \
+                         libxl__device_ ## sname ## _setdefault,               \
+        .to_device     = (int (*)(libxl__gc *, uint32_t,                       \
+                                  void *, libxl__device *))                    \
+                         libxl__device_from_ ## name,                          \
+        .init          = (void (*)(void *))libxl_device_ ## sname ## _init,    \
+        .copy          = (void (*)(libxl_ctx *, void *, void *))               \
+                         libxl_device_ ## sname ## _copy,                      \
         .dispose       = (void (*)(void *))libxl_device_ ## sname ## _dispose, \
         .compare       = (int (*)(void *, void *))                             \
                          libxl_device_ ## sname ## _compare,                   \
@@ -3523,6 +3538,7 @@  extern const struct libxl_device_type libxl__vtpm_devtype;
 extern const struct libxl_device_type libxl__usbctrl_devtype;
 extern const struct libxl_device_type libxl__usbdev_devtype;
 extern const struct libxl_device_type libxl__pcidev_devtype;
+extern const struct libxl_device_type libxl__vdispl_devtype;
 
 extern const struct libxl_device_type *device_type_tbl[];
 
@@ -4339,6 +4355,14 @@  static inline bool libxl__acpi_defbool_val(const libxl_domain_build_info *b_info
     return libxl_defbool_val(b_info->acpi) &&
            libxl_defbool_val(b_info->u.hvm.acpi);
 }
+
+void libxl__device_add(libxl__egc *egc, uint32_t domid,
+                       const struct libxl_device_type *dt, void *type,
+                       libxl__ao_device *aodev);
+void* libxl__device_list(const struct libxl_device_type *dt,
+                         libxl_ctx *ctx, uint32_t domid, int *num);
+void libxl__device_list_free(const struct libxl_device_type *dt,
+                             void *list, int num);
 #endif
 
 /*
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 2475a4d..d5684a6 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -738,7 +738,21 @@  libxl_device_vtpm = Struct("device_vtpm", [
     ("backend_domname",  string),
     ("devid",            libxl_devid),
     ("uuid",             libxl_uuid),
-])
+    ])
+
+libxl_connector_param = Struct("connector_param", [
+    ("id", string),
+    ("width", uint32),
+    ("height", uint32)
+    ])
+
+libxl_device_vdispl = Struct("device_vdispl", [
+    ("backend_domid", libxl_domid),
+    ("backend_domname", string),
+    ("devid", libxl_devid),
+    ("be_alloc", bool),
+    ("connectors", Array(libxl_connector_param, "num_connectors"))
+    ])
 
 libxl_device_channel = Struct("device_channel", [
     ("backend_domid", libxl_domid),
@@ -750,7 +764,7 @@  libxl_device_channel = Struct("device_channel", [
             ("pty", None),
             ("socket", Struct(None, [("path", string)])),
            ])),
-])
+    ])
 
 libxl_domain_config = Struct("domain_config", [
     ("c_info", libxl_domain_create_info),
@@ -764,6 +778,7 @@  libxl_domain_config = Struct("domain_config", [
     ("vfbs", Array(libxl_device_vfb, "num_vfbs")),
     ("vkbs", Array(libxl_device_vkb, "num_vkbs")),
     ("vtpms", Array(libxl_device_vtpm, "num_vtpms")),
+    ("vdispls", Array(libxl_device_vdispl, "num_vdispls")),
     # a channel manifests as a console with a name,
     # see docs/misc/channels.txt
     ("channels", Array(libxl_device_channel, "num_channels")),
@@ -860,6 +875,27 @@  libxl_physinfo = Struct("physinfo", [
     ("cap_hvm_directio", bool),
     ], dir=DIR_OUT)
 
+libxl_connectorinfo = Struct("connectorinfo", [
+    ("id", string),
+    ("width", uint32),
+    ("height", uint32),
+    ("req_evtch", integer),
+    ("req_rref", integer),
+    ("evt_evtch", integer),
+    ("evt_rref", integer),
+    ], dir=DIR_OUT)
+
+libxl_vdisplinfo = Struct("vdisplinfo", [
+    ("backend", string),
+    ("backend_id", uint32),
+    ("frontend", string),
+    ("frontend_id", uint32),
+    ("devid", libxl_devid),
+    ("state", integer),
+    ("be_alloc", bool),
+    ("connectors", Array(libxl_connectorinfo, "num_connectors"))
+    ], dir=DIR_OUT)
+
 # NUMA node characteristics: size and free are how much memory it has, and how
 # much of it is free, respectively. dists is an array of distances from this
 # node to each other node.
diff --git a/tools/libxl/libxl_types_internal.idl b/tools/libxl/libxl_types_internal.idl
index 82e5c07..cdef4d3 100644
--- a/tools/libxl/libxl_types_internal.idl
+++ b/tools/libxl/libxl_types_internal.idl
@@ -25,6 +25,7 @@  libxl__device_kind = Enumeration("device_kind", [
     (8, "VTPM"),
     (9, "VUSB"),
     (10, "QUSB"),
+    (11, "VDISPL")
     ])
 
 libxl__console_backend = Enumeration("console_backend", [
diff --git a/tools/libxl/libxl_usb.c b/tools/libxl/libxl_usb.c
index d8948d5..d1ec28f 100644
--- a/tools/libxl/libxl_usb.c
+++ b/tools/libxl/libxl_usb.c
@@ -1968,6 +1968,8 @@  void libxl_device_usbdev_list_free(libxl_device_usbdev *list, int nr)
 DEFINE_DEVICE_TYPE_STRUCT(usbctrl,
     .dm_needed = libxl_device_usbctrl_dm_needed
 );
+
+#define libxl__device_from_usbdev NULL
 DEFINE_DEVICE_TYPE_STRUCT(usbdev);
 
 /*
diff --git a/tools/libxl/libxl_utils.h b/tools/libxl/libxl_utils.h
index 25773d8..9e743dc 100644
--- a/tools/libxl/libxl_utils.h
+++ b/tools/libxl/libxl_utils.h
@@ -78,6 +78,10 @@  int libxl_devid_to_device_vtpm(libxl_ctx *ctx, uint32_t domid,
                                int devid, libxl_device_vtpm *vtpm);
 int libxl_devid_to_device_usbctrl(libxl_ctx *ctx, uint32_t domid,
                                   int devid, libxl_device_usbctrl *usbctrl);
+
+int libxl_devid_to_device_vdispl(libxl_ctx *ctx, uint32_t domid,
+                                 int devid, libxl_device_vdispl *vdispl);
+
 int libxl_ctrlport_to_device_usbdev(libxl_ctx *ctx, uint32_t domid,
                                     int ctrl, int port,
                                     libxl_device_usbdev *usbdev);
diff --git a/tools/libxl/libxl_vdispl.c b/tools/libxl/libxl_vdispl.c
new file mode 100644
index 0000000..d816413
--- /dev/null
+++ b/tools/libxl/libxl_vdispl.c
@@ -0,0 +1,372 @@ 
+/*
+ * Copyright (C) 2016 EPAM Systems Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; version 2.1 only. with the special
+ * exception on linking described in file LICENSE.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ */
+
+#include "libxl_osdeps.h"
+
+#include "libxl_internal.h"
+
+static int libxl__device_vdispl_setdefault(libxl__gc *gc, uint32_t domid,
+                                           libxl_device_vdispl *vdispl)
+{
+    int rc;
+
+    rc = libxl__resolve_domid(gc, vdispl->backend_domname,
+                              &vdispl->backend_domid);
+
+    if (vdispl->devid == -1) {
+        vdispl->devid = libxl__device_nextid(gc, domid, "vdispl");
+    }
+
+    return rc;
+}
+
+static int libxl__from_xenstore_vdispl(libxl__gc *gc, const char *be_path,
+                                       uint32_t devid,
+                                       libxl_device_vdispl *vdispl)
+{
+    vdispl->devid = devid;
+
+    return libxl__backendpath_parse_domid(gc, be_path, &vdispl->backend_domid);
+}
+
+static int libxl__device_from_vdispl(libxl__gc *gc, uint32_t domid,
+                                     libxl_device_vdispl *vdispl,
+                                     libxl__device *device)
+{
+   device->backend_devid   = vdispl->devid;
+   device->backend_domid   = vdispl->backend_domid;
+   device->backend_kind    = LIBXL__DEVICE_KIND_VDISPL;
+   device->devid           = vdispl->devid;
+   device->domid           = domid;
+   device->kind            = LIBXL__DEVICE_KIND_VDISPL;
+
+   return 0;
+}
+
+static int libxl__set_xenstore_connectors(libxl__gc *gc, xs_transaction_t t,
+                                          libxl__device *device,
+                                          libxl_device_vdispl *vdispl)
+{
+    struct xs_permissions perms[2];
+    char *frontend_path = NULL;
+    flexarray_t *connector;
+    libxl_ctx *ctx = libxl__gc_owner(gc);
+    int i;
+    int rc;
+
+    frontend_path = libxl__device_frontend_path(gc, device);
+
+    perms[0].id = device->domid;
+    perms[0].perms = XS_PERM_NONE;
+    perms[1].id = device->backend_domid;
+    perms[1].perms = XS_PERM_READ;
+
+    connector = flexarray_make(gc, 2, 1);
+    flexarray_append(connector, "resolution");
+    flexarray_append(connector, "");
+    flexarray_append(connector, "id");
+    flexarray_append(connector, "");
+
+    for (i = 0; i < vdispl->num_connectors; i++) {
+        char *connector_path = GCSPRINTF("%s/%d", frontend_path, i);
+
+        if (!xs_mkdir(ctx->xsh, t, connector_path)) {
+            rc = ERROR_FAIL; goto out;
+        }
+
+        if (!xs_set_permissions(ctx->xsh, t, connector_path, perms,
+                                ARRAY_SIZE(perms))) {
+            rc = ERROR_FAIL; goto out;
+        }
+
+        flexarray_set(connector, 1,
+                      GCSPRINTF("%dx%d", vdispl->connectors[i].width,
+                                 vdispl->connectors[i].height));
+        flexarray_set(connector, 3, vdispl->connectors[i].id);
+
+        rc = libxl__xs_writev(gc, t, connector_path,
+                              libxl__xs_kvs_of_flexarray(gc, connector));
+        if (rc) goto out;
+    }
+
+    rc = 0;
+
+out:
+    return rc;
+}
+
+static int libxl__set_xenstore_vdispl(libxl__gc *gc, uint32_t domid,
+                                      libxl_device_vdispl *vdispl)
+{
+    flexarray_t *front;
+    flexarray_t *back;
+
+    front = flexarray_make(gc, 16, 1);
+    back = flexarray_make(gc, 16, 1);
+
+    flexarray_append(back, "frontend-id");
+    flexarray_append(back, GCSPRINTF("%d", domid));
+    flexarray_append(back, "online");
+    flexarray_append(back, "1");
+    flexarray_append(back, "state");
+    flexarray_append(back, GCSPRINTF("%d", XenbusStateInitialising));
+    flexarray_append(back, "handle");
+    flexarray_append(back, GCSPRINTF("%d", vdispl->devid));
+
+    flexarray_append(front, "backend-id");
+    flexarray_append(front, GCSPRINTF("%d", vdispl->backend_domid));
+    flexarray_append(front, "state");
+    flexarray_append(front, GCSPRINTF("%d", XenbusStateInitialising));
+    flexarray_append(front, "handle");
+    flexarray_append(front, GCSPRINTF("%d", vdispl->devid));
+    flexarray_append(front, "be_alloc");
+    flexarray_append(front, GCSPRINTF("%d", vdispl->be_alloc));
+
+    libxl__device *device;
+    xs_transaction_t t = XBT_NULL;
+    int rc;
+
+    GCNEW(device);
+
+    rc = libxl__device_from_vdispl(gc, domid, vdispl, device);
+    if (rc) goto out;
+
+    for (;;) {
+        rc = libxl__xs_transaction_start(gc, &t);
+        if (rc) goto out;
+
+        rc = libxl__device_generic_add(gc, t, device,
+                                       libxl__xs_kvs_of_flexarray(gc, back),
+                                       libxl__xs_kvs_of_flexarray(gc, front),
+                                       NULL);
+        if (rc) goto out;
+
+        rc = libxl__set_xenstore_connectors(gc, t, device, vdispl);
+        if (rc) goto out;
+
+        rc = libxl__xs_transaction_commit(gc, &t);
+        if (!rc) break;
+        if (rc < 0) goto out;
+    }
+
+    rc = 0;
+
+out:
+    libxl__xs_transaction_abort(gc, &t);
+    return rc;
+}
+
+static void libxl__update_config_vdispl(libxl__gc *gc,
+                                        libxl_device_vdispl *dst,
+                                        libxl_device_vdispl *src)
+{
+    dst->devid = src->devid;
+    dst->be_alloc = src->be_alloc;
+}
+
+static int libxl_device_vdispl_compare(libxl_device_vdispl *d1,
+                                       libxl_device_vdispl *d2)
+{
+    return COMPARE_DEVID(d1, d2);
+}
+
+static void libxl__device_vdispl_add(libxl__egc *egc, uint32_t domid,
+                                     libxl_device_vdispl *vdispl,
+                                     libxl__ao_device *aodev)
+{
+    libxl__device_add(egc, domid, &libxl__vdispl_devtype, vdispl, aodev);
+}
+
+static int libxl__device_vdispl_getconnectors(libxl_ctx *ctx,
+                                              const char *path,
+                                              libxl_vdisplinfo *info)
+{
+    GC_INIT(ctx);
+    char *connector = NULL;
+    char *connector_path = NULL;
+    int i, rc;
+
+    GCNEW_ARRAY(connector_path, 128);
+
+    info->num_connectors = 0;
+
+    rc = snprintf(connector_path, 128, "%s/%d", path, info->num_connectors);
+    if (rc < 0) goto out;
+
+    while((connector = xs_read(ctx->xsh, XBT_NULL, connector_path, NULL))
+          != NULL) {
+        free(connector);
+
+        rc = snprintf(connector_path, 128, "%s/%d",
+                      path, ++info->num_connectors);
+        if (rc < 0) goto out;
+    }
+
+    info->connectors = libxl__calloc(NOGC, info->num_connectors,
+                                     sizeof(*info->connectors));
+
+    for (i = 0; i < info->num_connectors; i++) {
+        char *value;
+
+        snprintf(connector_path, 128, "%s/%d/id", path, i);
+        info->connectors[i].id = xs_read(ctx->xsh, XBT_NULL,
+                                         connector_path, NULL);
+        if (info->connectors[i].id == NULL) { rc = ERROR_FAIL; goto out; }
+
+        snprintf(connector_path, 128, "%s/%d/resolution", path, i);
+        value = xs_read(ctx->xsh, XBT_NULL, connector_path, NULL);
+        if (value == NULL) { rc = ERROR_FAIL; goto out; }
+
+        rc = sscanf(value, "%ux%u", &info->connectors[i].width,
+                   &info->connectors[i].height);
+        free(value);
+        if (rc != 2) {
+            rc = ERROR_FAIL; goto out;
+        }
+
+        snprintf(connector_path, 128, "%s/%d/req-ring-ref", path, i);
+        value = xs_read(ctx->xsh, XBT_NULL, connector_path, NULL);
+        info->connectors[i].req_rref = value ? strtoul(value, NULL, 10) : -1;
+        free(value);
+
+        snprintf(connector_path, 128, "%s/%d/req-event-channel", path, i);
+        value = xs_read(ctx->xsh, XBT_NULL, connector_path, NULL);
+        info->connectors[i].req_evtch = value ? strtoul(value, NULL, 10) : -1;
+        free(value);
+
+        snprintf(connector_path, 128, "%s/%d/evt-ring-ref", path, i);
+        value = xs_read(ctx->xsh, XBT_NULL, connector_path, NULL);
+        info->connectors[i].evt_rref = value ? strtoul(value, NULL, 10) : -1;
+        free(value);
+
+        snprintf(connector_path, 128, "%s/%d/evt-event-channel", path, i);
+        value = xs_read(ctx->xsh, XBT_NULL, connector_path, NULL);
+        info->connectors[i].evt_evtch = value ? strtoul(value, NULL, 10) : -1;
+        free(value);
+    }
+
+    rc = 0;
+
+out:
+    return rc;
+}
+
+libxl_device_vdispl *libxl_device_vdispl_list(libxl_ctx *ctx, uint32_t domid,
+                                              int *num)
+{
+    return libxl__device_list(&libxl__vdispl_devtype, ctx, domid, num);
+}
+
+void libxl_device_vdispl_list_free(libxl_device_vdispl* list, int num)
+{
+    libxl__device_list_free(&libxl__vdispl_devtype, list, num);
+}
+
+int libxl_device_vdispl_getinfo(libxl_ctx *ctx, uint32_t domid,
+                                libxl_device_vdispl *vdispl,
+                                libxl_vdisplinfo *info)
+{
+    GC_INIT(ctx);
+    char *libxl_path, *dompath, *devpath;
+    char *val;
+    int rc;
+
+    libxl_vdisplinfo_init(info);
+    dompath = libxl__xs_get_dompath(gc, domid);
+    info->devid = vdispl->devid;
+
+    devpath = GCSPRINTF("%s/device/vdispl/%d", dompath, info->devid);
+    libxl_path = GCSPRINTF("%s/device/vdispl/%d",
+                           libxl__xs_libxl_path(gc, domid),
+                           info->devid);
+    info->backend = xs_read(ctx->xsh, XBT_NULL,
+                            GCSPRINTF("%s/backend", libxl_path),
+                            NULL);
+    if (!info->backend) { rc = ERROR_FAIL; goto out; }
+
+    rc = libxl__backendpath_parse_domid(gc, info->backend, &info->backend_id);
+    if (rc) goto out;
+
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/state", devpath));
+    info->state = val ? strtoul(val, NULL, 10) : -1;
+
+    info->frontend = xs_read(ctx->xsh, XBT_NULL,
+                             GCSPRINTF("%s/frontend", libxl_path),
+                             NULL);
+    info->frontend_id = domid;
+
+    val = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/be_alloc", devpath));
+    info->be_alloc = val ? strtoul(val, NULL, 10) : 0;
+
+    rc = libxl__device_vdispl_getconnectors(ctx, devpath, info);
+    if (rc) goto out;
+
+    rc = 0;
+
+out:
+     GC_FREE;
+     return rc;
+}
+
+int libxl_devid_to_device_vdispl(libxl_ctx *ctx, uint32_t domid,
+                                 int devid, libxl_device_vdispl *vdispl)
+{
+    libxl_device_vdispl *vdispls = NULL;
+    int n, i;
+    int rc;
+
+    libxl_device_vdispl_init(vdispl);
+
+    vdispls = libxl_device_vdispl_list(ctx, domid, &n);
+
+    if (!vdispls) { rc = ERROR_NOTFOUND; goto out; }
+
+    for (i = 0; i < n; ++i) {
+        if (devid == vdispls[i].devid) {
+            libxl_device_vdispl_copy(ctx, vdispl, &vdispls[i]);
+            rc = 0;
+            goto out;
+        }
+    }
+
+    rc = ERROR_NOTFOUND;
+
+out:
+
+    if (vdispls) {
+        libxl_device_vdispl_list_free(vdispls, n);
+    }
+    return rc;
+}
+
+LIBXL_DEFINE_DEVICE_ADD(vdispl)
+static LIBXL_DEFINE_DEVICES_ADD(vdispl)
+LIBXL_DEFINE_DEVICE_REMOVE(vdispl)
+
+DEFINE_DEVICE_TYPE_STRUCT(vdispl,
+    .update_config = (void (*)(libxl__gc *, void *, void *))
+                     libxl__update_config_vdispl,
+    .from_xenstore = (int (*)(libxl__gc *, const char *, uint32_t, void *))
+                     libxl__from_xenstore_vdispl,
+    .set_xenstore_config = (int (*)(libxl__gc *, uint32_t, void *))
+                           libxl__set_xenstore_vdispl
+);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */