---
 include/libvirt/virterror.h         |   1 +
 po/POTFILES.in                      |   2 +
 src/jailhouse/Makefile.inc.am       |  34 ++-
 src/jailhouse/jailhouse.conf        |  10 +
 src/jailhouse/jailhouse_api.c       | 372 ++++++++++++++++++++++++++++
 src/jailhouse/jailhouse_api.h       |  74 ++++++
 src/jailhouse/jailhouse_driver.c    | 302 +++++++++++++++++-----
 src/jailhouse/jailhouse_driver.h    |  51 ++++
 src/jailhouse/meson.build           |   1 +
 src/libvirt.c                       |  10 -
 src/remote/remote_daemon.c          |   4 +
 src/remote/remote_daemon_dispatch.c |   3 +-
 12 files changed, 783 insertions(+), 81 deletions(-)
 create mode 100644 src/jailhouse/jailhouse.conf
 create mode 100644 src/jailhouse/jailhouse_api.c
 create mode 100644 src/jailhouse/jailhouse_api.h

diff --git a/include/libvirt/virterror.h b/include/libvirt/virterror.h
index 97f2ac16d8..9f1bca2684 100644
--- a/include/libvirt/virterror.h
+++ b/include/libvirt/virterror.h
@@ -137,6 +137,7 @@ typedef enum {
     VIR_FROM_TPM = 70,          /* Error from TPM */
     VIR_FROM_BPF = 71,          /* Error from BPF code */
     VIR_FROM_JAILHOUSE = 72,    /* Error from Jailhouse driver */
+
 # ifdef VIR_ENUM_SENTINELS
     VIR_ERR_DOMAIN_LAST
 # endif
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 3d6c20c55f..a94285817f 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -85,6 +85,8 @@
 @SRCDIR@src/interface/interface_backend_netcf.c
 @SRCDIR@src/interface/interface_backend_udev.c
 @SRCDIR@src/internal.h
+@SRCDIR@src/jailhouse/jailhouse_api.c
+@SRCDIR@src/jailhouse/jailhouse_driver.c
 @SRCDIR@src/libvirt-domain-checkpoint.c
 @SRCDIR@src/libvirt-domain-snapshot.c
 @SRCDIR@src/libvirt-domain.c
diff --git a/src/jailhouse/Makefile.inc.am b/src/jailhouse/Makefile.inc.am
index 02822b2ea1..324c3b1b16 100644
--- a/src/jailhouse/Makefile.inc.am
+++ b/src/jailhouse/Makefile.inc.am
@@ -1,8 +1,11 @@
 # vim: filetype=automake

+
 JAILHOUSE_DRIVER_SOURCES = \
        jailhouse/jailhouse_driver.c \
        jailhouse/jailhouse_driver.h \
+       jailhouse/jailhouse_api.c \
+       jailhouse/jailhouse_api.h \
        $(NULL)


@@ -11,11 +14,34 @@ DRIVER_SOURCE_FILES += $(addprefix $(srcdir)/,$(JAILHOUSE_DRIVER_SOURCES))
 EXTRA_DIST += $(JAILHOUSE_DRIVER_SOURCES)

 if WITH_JAILHOUSE
-noinst_LTLIBRARIES += libvirt_driver_jailhouse.la
-libvirt_la_BUILT_LIBADD += libvirt_driver_jailhouse.la
-libvirt_driver_jailhouse_la_CFLAGS = \
+
+noinst_LTLIBRARIES += libvirt_driver_jailhouse_impl.la
+libvirt_driver_jailhouse_la_SOURCES =
+libvirt_driver_jailhouse_la_LIBADD = \
+       libvirt_driver_jailhouse_impl.la \
+       libvirt.la \
+       $(GLIB_LIBS) \
+       $(NULL)
+mod_LTLIBRARIES += libvirt_driver_jailhouse.la
+libvirt_driver_jailhouse_la_LDFLAGS = $(AM_LDFLAGS_MOD_NOUNDEF)
+
+libvirt_driver_jailhouse_impl_la_CFLAGS = \
        -I$(srcdir)/conf \
        $(AM_CFLAGS) \
        $(NULL)
-libvirt_driver_jailhouse_la_SOURCES = $(JAILHOUSE_DRIVER_SOURCES)
+libvirt_driver_jailhouse_impl_la_SOURCES = \
+       $(JAILHOUSE_DRIVER_SOURCES)
+
+sbin_PROGRAMS += virtjailhoused
+
+virtjailhoused_SOURCES = $(REMOTE_DAEMON_SOURCES)
+nodist_virtjailhoused_SOURCES = $(REMOTE_DAEMON_GENERATED)
+virtjailhoused_CFLAGS = \
+       $(REMOTE_DAEMON_CFLAGS) \
+       -DDAEMON_NAME="\"virtjailhoused\"" \
+       -DMODULE_NAME="\"jailhouse\"" \
+       $(NULL)
+virtjailhoused_LDFLAGS = $(REMOTE_DAEMON_LD_FLAGS)
+virtjailhoused_LDADD = $(REMOTE_DAEMON_LD_ADD)
+
 endif WITH_JAILHOUSE
diff --git a/src/jailhouse/jailhouse.conf b/src/jailhouse/jailhouse.conf
new file mode 100644
index 0000000000..587068b9d0
--- /dev/null
+++ b/src/jailhouse/jailhouse.conf
@@ -0,0 +1,10 @@
+# Configuration for the Jailhouse driver.
+
+# Jailhouse system configuration file to enable the Jailhouse hypervisor on the
+# system. This is a required configuration parameter for the driver.
+#system_config = "/etc/libvirt/jailhouse/qemu-x86.cell"
+
+# Specify a directory which contains all the non-root cell configurations which
+# should be created by the driver at the startup. This is optional. Default
+# value of "/etc/libvirt/jailhouse/cells/" will be used if left empty.
+#non_root_cells_dir = "/etc/libvirt/jailhouse/cells/"
diff --git a/src/jailhouse/jailhouse_api.c b/src/jailhouse/jailhouse_api.c
new file mode 100644
index 0000000000..cda00b50e7
--- /dev/null
+++ b/src/jailhouse/jailhouse_api.c
@@ -0,0 +1,372 @@
+/*
+ * jailhouse_api.c: Jailhouse API
+ *
+ * Copyright (C) 2020 Prakhar Bansal
+ *
+ * This library 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; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <linux/types.h>
+
+#include "viralloc.h"
+#include "virerror.h"
+#include "virfile.h"
+#include "virlog.h"
+#include "virstring.h"
+#include "jailhouse_api.h"
+
+#define JAILHOUSE_DEVICE                        "/dev/jailhouse"
+#define JAILHOUSE_CELLS                         "/sys/devices/jailhouse/cells"
+#define MAX_JAILHOUSE_SYS_CONFIG_FILE_SIZE      1024*1024
+#define MAX_JAILHOUSE_CELL_CONFIG_FILE_SIZE     1024
+
+
+#define JAILHOUSE_ENABLE               _IOW(0, 0, void *)
+#define JAILHOUSE_DISABLE              _IO(0, 1)
+#define JAILHOUSE_CELL_CREATE          _IOW(0, 2, virJailhouseCellCreate)
+#define JAILHOUSE_CELL_DESTROY         _IOW(0, 5, virJailhouseCellId)
+
+#define VIR_FROM_THIS VIR_FROM_JAILHOUSE
+
+VIR_LOG_INIT("jailhouse.jailhouse_api");
+
+#define JAILHOUSE_CELL_FILE_EXTENSION ".cell"
+
+/* Forward declarations */
+
+/* Open the Jailhouse device for ioctl APIs */
+int openDev(void);
+
+/* Reads cell's property given by 'entry' using sysfs API */
+char *readSysfsCellString(const unsigned int id, const char *entry);
+
+int cell_match(const struct dirent *dirent);
+
+int createCell(const char *conf_file);
+
+int destroyCell(virJailhouseCellId cell_id);
+
+int getCellInfo(const unsigned int id,
+                virJailhouseCellInfoPtr * cell_info);
+
+int
+jailhouseEnable(const char *sys_conf_file_path)
+{
+    int err = -1, len;
+    g_autofree char *buffer = NULL;
+    VIR_AUTOCLOSE fd = -1;
+
+    if (!virFileExists(sys_conf_file_path))
+        return 0;
+
+    len = virFileReadAll(sys_conf_file_path, MAX_JAILHOUSE_SYS_CONFIG_FILE_SIZE, &buffer);
+    if (len < 0 || !buffer) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                      "%s", _("Failed to read the system configuration file"));
+        return -1;
+    }
+
+    fd = openDev();
+
+    err = ioctl(fd, JAILHOUSE_ENABLE, buffer);
+    if (err) {
+        virReportSystemError(errno, "%s", _("Failed to enable jailhouse"));
+        return err;
+    }
+
+    VIR_DEBUG("Jailhouse hypervisor is enabled");
+
+    return 1;
+}
+
+int
+jailhouseDisable(void)
+{
+    int err = -1;
+    VIR_AUTOCLOSE fd = -1;
+
+    fd = openDev();
+
+    err = ioctl(fd, JAILHOUSE_DISABLE);
+    if (err)
+        virReportSystemError(errno,
+                             "%s",
+                             _("Failed to disable jailhouse: %s"));
+
+    VIR_DEBUG("Jailhouse hypervisor is disabled");
+
+    return err;
+}
+
+int
+cell_match(const struct dirent *dirent)
+{
+    char *ext = strrchr(dirent->d_name, '.');
+
+    return dirent->d_name[0] != '.'
+        && (STREQ(ext, JAILHOUSE_CELL_FILE_EXTENSION) == 0);
+}
+
+int
+createJailhouseCells(const char *dir_path)
+{
+
+    struct dirent **namelist;
+    int num_entries, ret = -1;
+    size_t i;
+
+    if (strlen(dir_path) == 0)
+        return ret;
+
+    num_entries = scandir(dir_path, &namelist, cell_match, alphasort);
+    if (num_entries == -1) {
+        if (errno == ENOENT) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("No cells found in %s, scandir failed."),
+                           dir_path);
+            goto fail;
+        }
+
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                       _("Error reading cell configurations in %s."),
+                       dir_path);
+        goto fail;
+    }
+
+
+    for (i = 0; i < num_entries; i++) {
+        g_autofree char *file_path = g_strdup_printf("%s/%s", dir_path, namelist[i]->d_name);
+
+        if (createCell(file_path) != 0) {
+            virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                           _("Cell creation failed with conf found in  %s."),
+                           namelist[i]->d_name);
+            goto fail;
+        }
+    }
+
+    ret = 0;
+
+ fail:
+    VIR_FREE(namelist);
+    return ret;
+}
+
+int
+openDev(void)
+{
+    int fd;
+
+    fd = open(JAILHOUSE_DEVICE, O_RDWR);
+    if (fd < 0) {
+        virReportSystemError(errno,
+                             _("Error opening jailhouse device %s"),
+                             JAILHOUSE_DEVICE);
+    }
+    return fd;
+}
+
+int
+createCell(const char *conf_file)
+{
+    virJailhouseCellCreate cell_create;
+    int err = -1, len;
+    g_autofree char *buffer = NULL;
+    VIR_AUTOCLOSE fd = -1;
+
+    if (strlen(conf_file) == 0)
+        return err;
+
+    len = virFileReadAll(conf_file, MAX_JAILHOUSE_CELL_CONFIG_FILE_SIZE, &buffer);
+    if (len < 0 || !buffer) {
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+                      "%s", _("Failed to read the system configuration file"));
+        return err;
+    }
+
+    cell_create.config_address = (unsigned long) buffer;
+    cell_create.config_size = len;
+
+    fd = openDev();
+
+    err = ioctl(fd, JAILHOUSE_CELL_CREATE, &cell_create);
+    if (err)
+        virReportSystemError(errno,
+                             "%s",
+                             _("Cell creation failed: %s"));
+
+    return err;
+}
+
+void
+cellInfoFree(virJailhouseCellInfoPtr cell_info)
+{
+    VIR_FREE(cell_info->state);
+    VIR_FREE(cell_info->cpus_assigned_list);
+    VIR_FREE(cell_info->cpus_failed_list);
+    VIR_FREE(cell_info);
+}
+
+char *
+readSysfsCellString(const unsigned int id, const char *entry)
+{
+    g_autofree char *buffer = NULL;
+    g_autofree char *file_path = NULL;
+    int len = -1;
+
+    file_path = g_strdup_printf(JAILHOUSE_CELLS "%u/%s", id, entry);
+
+    len = virFileReadAll(file_path, 1024, &buffer);
+    if (len < 0 || !buffer) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Error reading cell(%u) %s from %s failed"),
+                       id, entry, file_path);
+        return NULL;
+    }
+
+    virTrimSpaces(buffer, NULL);
+
+    return buffer;
+}
+
+int
+getCellInfo(const unsigned int id, virJailhouseCellInfoPtr * cell_info_ptr)
+{
+    char *tmp;
+
+    if (VIR_ALLOC(*cell_info_ptr) < 0)
+        return -1;
+
+    virJailhouseCellInfoPtr cell_info = *cell_info_ptr;
+
+    /* set cell id */
+    cell_info->id.id = id;
+
+    /* get cell name */
+    tmp = readSysfsCellString(id, "name");
+    if (virStrncpy(cell_info->id.name, tmp, JAILHOUSE_CELL_ID_NAMELEN, JAILHOUSE_CELL_ID_NAMELEN) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Cell ID %s too long to be copied to the cell info"),
+                       tmp);
+        return -1;
+    }
+
+    cell_info->id.name[JAILHOUSE_CELL_ID_NAMELEN] = 0;
+    VIR_FREE(tmp);
+
+    /* get cell state */
+    cell_info->state = readSysfsCellString(id, "state");
+
+    /* get assigned cpu list */
+    cell_info->cpus_assigned_list =
+        readSysfsCellString(id, "cpus_assigned_list");
+
+    /* get failed cpu list */
+    cell_info->cpus_failed_list =
+        readSysfsCellString(id, "cpus_failed_list");
+
+    return 0;
+}
+
+virJailhouseCellInfoPtr *
+getJailhouseCellsInfo(void)
+{
+    struct dirent **namelist;
+    virJailhouseCellInfoPtr *cell_info_list;
+    unsigned int id;
+    int num_entries;
+    size_t i;
+
+    num_entries =
+        scandir(JAILHOUSE_CELLS, &namelist, cell_match, alphasort);
+    if (num_entries == -1) {
+        if (errno == ENOENT) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("No cells found in %s, scandir failed."),
+                           JAILHOUSE_CELLS);
+            return NULL;
+        }
+
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       _("Error reading cell IDs in %s."),
+                       JAILHOUSE_CELLS);
+        return NULL;
+    }
+
+    /* Allocate memory for 1 more than num_entries and make the last entry NULL. */
+    if (VIR_ALLOC_N(cell_info_list, num_entries + 1) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR,
+                       "%s",
+                       _("Insufficient memory for cells info list"));
+    }
+
+    /* Set the last entry to NULL. */
+    cell_info_list[num_entries] = NULL;
+
+    for (i = 0; i < num_entries; i++) {
+        if (virStrToLong_ui(namelist[i]->d_name, NULL, 10, &id) < 0) {
+            virReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("Cell ID %s could not be converted to a long"),
+                           namelist[i]->d_name);
+            continue;
+        }
+
+        /* get the cell's information(name, state etc.) using sysfs */
+        getCellInfo(id, &cell_info_list[i]);
+        VIR_FREE(namelist[i]);
+    }
+
+    VIR_FREE(namelist);
+    return cell_info_list;
+}
+
+int
+destroyCell(virJailhouseCellId cell_id)
+{
+    int err = -1;
+    VIR_AUTOCLOSE fd = -1;
+
+    fd = openDev();
+
+    err = ioctl(fd, JAILHOUSE_CELL_DESTROY, &cell_id);
+    if (err)
+        virReportSystemError(errno,
+                             _("Destroying cell %d failed"),
+                             cell_id.id);
+
+    return err;
+}
+
+int
+destroyJailhouseCells(virJailhouseCellInfoPtr *cell_info_list G_GNUC_UNUSED)
+{
+
+    /* Iterate over all cells in cell_info_list and destroy each cell */
+    // TODO: Not implemented yet.
+
+    return 0;
+}
diff --git a/src/jailhouse/jailhouse_api.h b/src/jailhouse/jailhouse_api.h
new file mode 100644
index 0000000000..8362cb3d0f
--- /dev/null
+++ b/src/jailhouse/jailhouse_api.h
@@ -0,0 +1,74 @@
+/*
+ * jailhouse_api.h: Jailhouse hypervisor API implementation
+ *
+ * Copyright (C) 2020 Prakhar Bansal
+ *
+ * This library 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; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#define JAILHOUSE_CELL_ID_NAMELEN       31
+
+typedef struct _virJailhouseCellId virJailhouseCellId;
+
+struct _virJailhouseCellId {
+    __s32 id;
+    __u32 padding;
+    char name[JAILHOUSE_CELL_ID_NAMELEN + 1];
+};
+
+typedef struct _virJailhouseCellInfo virJailhouseCellInfo;
+typedef virJailhouseCellInfo *virJailhouseCellInfoPtr;
+
+struct _virJailhouseCellInfo {
+    struct _virJailhouseCellId id;
+    char *state;
+    char *cpus_assigned_list;
+    char *cpus_failed_list;
+};
+
+typedef struct _virJailhouseCellCreate virJailhouseCellCreate;
+
+struct _virJailhouseCellCreate {
+    __u64 config_address;
+    __u32 config_size;
+    __u32 padding;
+};
+
+// Enables the Jailhouse hypervisor by reading the hypervisor system
+// configuration from the given file and calls the ioctl API to
+// enable the hypervisor.
+int jailhouseEnable(const char *sys_conf_file_path);
+
+// Disables the Jailhouse hypervisor.
+int jailhouseDisable(void);
+
+/* Cell API methods */
+
+// Creates Jailhouse cells using the cells configurations
+// provided in the dir_name.
+int createJailhouseCells(const char *dir_path);
+
+// Destroys Jailhouse cells using the cell IDs provided in
+// the cell_info_list.
+int destroyJailhouseCells(virJailhouseCellInfoPtr *cell_info_list);
+
+// Returns cell's information in a null-terminated array of
+// virJailhouseCellInfoPtr for all the Jailhouse cells.
+virJailhouseCellInfoPtr *getJailhouseCellsInfo(void);
+
+// Free the cell info object.
+void cellInfoFree(virJailhouseCellInfoPtr cell_info);
diff --git a/src/jailhouse/jailhouse_driver.c b/src/jailhouse/jailhouse_driver.c
index 0175ba771b..ac9da4c85d 100644
--- a/src/jailhouse/jailhouse_driver.c
+++ b/src/jailhouse/jailhouse_driver.c
@@ -16,43 +16,228 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this library.  If not, see
  * <http://www.gnu.org/licenses/>.
+ *
  */

 #include <config.h>
+#include <string.h>

+#include "configmake.h"
+#include "datatypes.h"
+#include "domain_conf.h"
 #include "jailhouse_driver.h"
 #include "virtypedparam.h"
 #include "virerror.h"
 #include "virstring.h"
 #include "viralloc.h"
-#include "domain_conf.h"
 #include "virfile.h"
-#include "datatypes.h"
+#include "virlog.h"
 #include "vircommand.h"
-#include <string.h>
+#include "virpidfile.h"

-#define UNUSED(x) (void)(x)
+#define VIR_FROM_THIS VIR_FROM_JAILHOUSE
+
+VIR_LOG_INIT("jailhouse.jailhouse_driver");
+
+static virClassPtr virJailhouseDriverConfigClass;
+static void virJailhouseDriverConfigDispose(void *obj);
+
+static virJailhouseDriverPtr jailhouse_driver;
+
+static int virJailhouseConfigOnceInit(void)
+{
+    if (!VIR_CLASS_NEW(virJailhouseDriverConfig, virClassForObject()))
+        return -1;
+
+    return 0;
+}
+
+VIR_ONCE_GLOBAL_INIT(virJailhouseConfig);
+
+
+static virJailhouseDriverConfigPtr
+virJailhouseDriverConfigNew(void)
+{
+    virJailhouseDriverConfigPtr cfg;
+
+    // TODO: Check if the following has to be uncommented.
+    if (virJailhouseConfigInitialize() < 0)
+        return NULL;
+
+    if (!(cfg = virObjectNew(virJailhouseDriverConfigClass)))
+        return NULL;
+
+    cfg->stateDir = g_strdup(JAILHOUSE_STATE_DIR);
+
+    cfg->sys_config_file_path = g_strdup(DATADIR "/jailhouse/system.cell");
+
+    cfg->cell_config_dir = g_strdup(DATADIR "/jailhouse/cells");
+
+    return cfg;
+}
+
+static void virJailhouseDriverConfigDispose(void *obj)
+{
+
+    virJailhouseDriverConfigPtr cfg = obj;
+
+    VIR_FREE(cfg->stateDir);
+    VIR_FREE(cfg->sys_config_file_path);
+    VIR_FREE(cfg->cell_config_dir);
+}
+
+static int
+jailhouseLoadConf(virJailhouseDriverConfigPtr config)
+{
+    g_autoptr(virConf) conf = NULL;
+
+    if (!virFileExists(JAILHOUSE_CONFIG_FILE))
+        return 0;
+
+    if (!(conf = virConfReadFile(JAILHOUSE_CONFIG_FILE, 0)))
+        return -1;
+
+    if (virConfGetValueString(conf, "system_config",
+                              &config->sys_config_file_path) < 0)
+        return -1;
+
+    if (virConfGetValueString(conf, "non_root_cells_dir",
+                              &config->cell_config_dir) < 0)
+        return -1;
+
+    return 1;
+}
+
+static int
+jailhouseCreateAndLoadCells(virJailhouseDriverPtr driver)
+{
+    if (!driver->config ||
+        !driver->config->cell_config_dir ||
+        strlen(driver->config->cell_config_dir) == 0)
+        return -1;
+
+    // Create all cells in the hypervisor.
+    if (createJailhouseCells(driver->config->cell_config_dir) < 0)
+        return -1;
+
+    // Get all cells created above.
+    driver->cell_info_list = getJailhouseCellsInfo();
+
+    return 0;
+}
+
+static void
+jailhouseFreeDriver(virJailhouseDriverPtr driver)
+{
+    if (!driver)
+        return;
+
+    virMutexDestroy(&driver->lock);
+    virObjectUnref(driver->config);
+    VIR_FREE(driver);
+}

 static virDrvOpenStatus
 jailhouseConnectOpen(virConnectPtr conn,
-                     virConnectAuthPtr auth,
-                     virConfPtr conf,
-                     unsigned int flags)
+                     virConnectAuthPtr auth G_GNUC_UNUSED,
+                     virConfPtr conf G_GNUC_UNUSED, unsigned int flags)
 {
-    UNUSED(conn);
-    UNUSED(auth);
-    UNUSED(conf);
-    UNUSED(flags);
-    return 0;
+    uid_t uid = geteuid();
+
+    virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR);
+
+    if (!virConnectValidateURIPath(conn->uri->path, "jailhouse", uid == 0))
+        return VIR_DRV_OPEN_ERROR;
+
+    if (!jailhouse_driver) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("Jailhouse driver state is not initialized."));
+        return VIR_DRV_OPEN_ERROR;
+    }
+
+    conn->privateData = jailhouse_driver;
+
+    return VIR_DRV_OPEN_SUCCESS;
 }

+#define UNUSED(x) (void)(x)
+
 static int
 jailhouseConnectClose(virConnectPtr conn)
 {
-    UNUSED(conn);
+   conn->privateData = NULL;
+
+   return 0;
+}
+
+static int
+jailhouseStateCleanup(void)
+{
+    if (!jailhouse_driver)
+       return -1;
+
+    if (jailhouse_driver->lockFD != -1)
+        virPidFileRelease(jailhouse_driver->config->stateDir,
+                          "driver", jailhouse_driver->lockFD);
+
+    virMutexDestroy(&jailhouse_driver->lock);
+
+    jailhouseFreeDriver(jailhouse_driver);
     return 0;
 }

+static int
+jailhouseStateInitialize(bool privileged G_GNUC_UNUSED,
+                         const char *root G_GNUC_UNUSED,
+                         virStateInhibitCallback callback G_GNUC_UNUSED,
+                         void *opaque G_GNUC_UNUSED)
+{
+    virJailhouseDriverConfigPtr cfg = NULL;
+    int rc;
+
+    jailhouse_driver = g_new0(virJailhouseDriver, 1);
+    jailhouse_driver->lockFD = -1;
+
+    if (virMutexInit(&jailhouse_driver->lock) < 0) {
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+                       _("cannot initialize mutex"));
+        VIR_FREE(jailhouse_driver);
+        return VIR_DRV_STATE_INIT_ERROR;
+    }
+
+    if (!(cfg = virJailhouseDriverConfigNew()))
+        goto error;
+
+    jailhouse_driver->config = cfg;
+
+    if (jailhouseLoadConf(cfg) < 0)
+        goto error;
+
+    if (virFileMakePath(cfg->stateDir) < 0) {
+        virReportSystemError(errno, _("Failed to create state dir %s"),
+                             cfg->stateDir);
+        goto error;
+    }
+
+    if ((jailhouse_driver->lockFD = virPidFileAcquire(cfg->stateDir,
+                                                      "driver", false, getpid())) < 0)
+        goto error;
+
+    if ((rc = jailhouseEnable(cfg->sys_config_file_path)) < 0)
+        goto error;
+    else if (rc == 0)
+        return VIR_DRV_STATE_INIT_SKIPPED;
+
+    if (jailhouseCreateAndLoadCells(jailhouse_driver) < 0)
+        goto error;
+
+    return VIR_DRV_STATE_INIT_COMPLETE;
+
+ error:
+    jailhouseStateCleanup();
+    return VIR_DRV_STATE_INIT_ERROR;
+
+}
 static const char *
 jailhouseConnectGetType(virConnectPtr conn)
 {
@@ -69,36 +254,16 @@ jailhouseConnectGetHostname(virConnectPtr conn)
 }

 static int
-jailhouseNodeGetInfo(virConnectPtr conn,
-                     virNodeInfoPtr info)
+jailhouseNodeGetInfo(virConnectPtr conn, virNodeInfoPtr info)
 {
     UNUSED(conn);
     UNUSED(info);
     return -1;
 }

-static int
-jailhouseConnectListDomains(virConnectPtr conn,
-                            int *ids,
-                            int maxids)
-{
-    UNUSED(conn);
-    UNUSED(ids);
-    UNUSED(maxids);
-    return -1;
-}
-
-static int
-jailhouseConnectNumOfDomains(virConnectPtr conn)
-{
-    UNUSED(conn);
-    return -1;
-}
-
 static int
 jailhouseConnectListAllDomains(virConnectPtr conn,
-                               virDomainPtr **domain,
-                               unsigned int flags)
+                               virDomainPtr ** domain, unsigned int flags)
 {
     UNUSED(conn);
     UNUSED(domain);
@@ -107,8 +272,7 @@ jailhouseConnectListAllDomains(virConnectPtr conn,
 }

 static virDomainPtr
-jailhouseDomainLookupByID(virConnectPtr conn,
-                          int id)
+jailhouseDomainLookupByID(virConnectPtr conn, int id)
 {
     UNUSED(conn);
     UNUSED(id);
@@ -116,8 +280,7 @@ jailhouseDomainLookupByID(virConnectPtr conn,
 }

 static virDomainPtr
-jailhouseDomainLookupByName(virConnectPtr conn,
-                            const char *name)
+jailhouseDomainLookupByName(virConnectPtr conn, const char *name)
 {
     UNUSED(conn);
     UNUSED(name);
@@ -125,8 +288,7 @@ jailhouseDomainLookupByName(virConnectPtr conn,
 }

 static virDomainPtr
-jailhouseDomainLookupByUUID(virConnectPtr conn,
-                            const unsigned char *uuid)
+jailhouseDomainLookupByUUID(virConnectPtr conn, const unsigned char *uuid)
 {
     UNUSED(conn);
     UNUSED(uuid);
@@ -157,8 +319,7 @@ jailhouseDomainDestroy(virDomainPtr domain)
 }

 static int
-jailhouseDomainGetInfo(virDomainPtr domain,
-                       virDomainInfoPtr info)
+jailhouseDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info)
 {
     UNUSED(domain);
     UNUSED(info);
@@ -167,9 +328,7 @@ jailhouseDomainGetInfo(virDomainPtr domain,

 static int
 jailhouseDomainGetState(virDomainPtr domain,
-                        int *state,
-                        int *reason,
-                        unsigned int flags)
+                        int *state, int *reason, unsigned int flags)
 {
     UNUSED(domain);
     UNUSED(state);
@@ -179,8 +338,7 @@ jailhouseDomainGetState(virDomainPtr domain,
 }

 static char *
-jailhouseDomainGetXMLDesc(virDomainPtr domain,
-                          unsigned int flags)
+jailhouseDomainGetXMLDesc(virDomainPtr domain, unsigned int flags)
 {
     UNUSED(domain);
     UNUSED(flags);
@@ -189,31 +347,43 @@ jailhouseDomainGetXMLDesc(virDomainPtr domain,

 static virHypervisorDriver jailhouseHypervisorDriver = {
     .name = "JAILHOUSE",
-    .connectOpen = jailhouseConnectOpen, /* 6.3.0 */
-    .connectClose = jailhouseConnectClose, /* 6.3.0 */
-    .connectListDomains = jailhouseConnectListDomains, /* 6.3.0 */
-    .connectNumOfDomains = jailhouseConnectNumOfDomains, /* 6.3.0 */
-    .connectListAllDomains = jailhouseConnectListAllDomains, /* 6.3.0 */
-    .domainLookupByID = jailhouseDomainLookupByID, /* 6.3.0 */
-    .domainLookupByUUID = jailhouseDomainLookupByUUID, /* 6.3.0 */
-    .domainLookupByName = jailhouseDomainLookupByName, /* 6.3.0 */
-    .domainGetXMLDesc = jailhouseDomainGetXMLDesc, /* 6.3.0 */
-    .domainCreate = jailhouseDomainCreate, /* 6.3.0 */
-    .connectGetType = jailhouseConnectGetType, /* 6.3.0 */
-    .connectGetHostname = jailhouseConnectGetHostname, /* 6.3.0 */
-    .nodeGetInfo = jailhouseNodeGetInfo, /* 6.3.0 */
-    .domainShutdown = jailhouseDomainShutdown, /* 6.3.0 */
-    .domainDestroy = jailhouseDomainDestroy, /* 6.3.0 */
-    .domainGetInfo = jailhouseDomainGetInfo, /* 6.3.0 */
-    .domainGetState = jailhouseDomainGetState, /* 6.3.0 */
+    .connectOpen = jailhouseConnectOpen,        /* 6.3.0 */
+    .connectClose = jailhouseConnectClose,      /* 6.3.0 */
+    .connectListAllDomains = jailhouseConnectListAllDomains,    /* 6.3.0 */
+    .domainLookupByID = jailhouseDomainLookupByID,      /* 6.3.0 */
+    .domainLookupByUUID = jailhouseDomainLookupByUUID,  /* 6.3.0 */
+    .domainLookupByName = jailhouseDomainLookupByName,  /* 6.3.0 */
+    .domainGetXMLDesc = jailhouseDomainGetXMLDesc,      /* 6.3.0 */
+    .domainCreate = jailhouseDomainCreate,      /* 6.3.0 */
+    .connectGetType = jailhouseConnectGetType,  /* 6.3.0 */
+    .connectGetHostname = jailhouseConnectGetHostname,  /* 6.3.0 */
+    .nodeGetInfo = jailhouseNodeGetInfo,        /* 6.3.0 */
+    .domainShutdown = jailhouseDomainShutdown,  /* 6.3.0 */
+    .domainDestroy = jailhouseDomainDestroy,    /* 6.3.0 */
+    .domainGetInfo = jailhouseDomainGetInfo,    /* 6.3.0 */
+    .domainGetState = jailhouseDomainGetState,  /* 6.3.0 */
 };

+
 static virConnectDriver jailhouseConnectDriver = {
+    .localOnly = true,
+    .uriSchemes = (const char *[]){ "jailhouse", NULL },
     .hypervisorDriver = &jailhouseHypervisorDriver,
 };

+
+static virStateDriver jailhouseStateDriver = {
+    .name = "JAILHOUSE",
+    .stateInitialize = jailhouseStateInitialize,
+    .stateCleanup = jailhouseStateCleanup,
+};
+
 int
 jailhouseRegister(void)
 {
-    return virRegisterConnectDriver(&jailhouseConnectDriver, false);
+    if (virRegisterConnectDriver(&jailhouseConnectDriver, false) < 0)
+        return -1;
+    if (virRegisterStateDriver(&jailhouseStateDriver) < 0)
+        return -1;
+    return 0;
 }
diff --git a/src/jailhouse/jailhouse_driver.h b/src/jailhouse/jailhouse_driver.h
index b0dbc8d033..8a0e111676 100644
--- a/src/jailhouse/jailhouse_driver.h
+++ b/src/jailhouse/jailhouse_driver.h
@@ -20,4 +20,55 @@

 #pragma once

+#include <linux/types.h>
+
+#include "jailhouse_api.h"
+
 int jailhouseRegister(void);
+
+#define JAILHOUSE_CONFIG_FILE SYSCONFDIR "/libvirt/jailhouse/jailhouse.conf"
+#define JAILHOUSE_STATE_DIR RUNSTATEDIR "/libvirt/jailhouse"
+
+#define JAILHOUSE_DEV "/dev/jailhouse"
+
+#define JAILHOUSE_SYSFS_DEV "/sys/devices/jailhouse/"
+
+typedef struct _virJailhouseDriver virJailhouseDriver;
+typedef virJailhouseDriver *virJailhouseDriverPtr;
+
+typedef struct _virJailhouseDriverConfig virJailhouseDriverConfig;
+typedef virJailhouseDriverConfig *virJailhouseDriverConfigPtr;
+
+struct _virJailhouseDriverConfig {
+    virObject parent;
+
+    char *stateDir;
+
+    // File path of the jailhouse system configuration
+    // for jailhouse enable/disable.
+    char *sys_config_file_path;
+
+    // Config directory where all jailhouse cell configurations
+    // are stored.
+    char *cell_config_dir;
+};
+
+struct _virJailhouseDriver {
+    virMutex lock;
+
+    // Jailhouse configuration read from the jailhouse.conf
+    virJailhouseDriverConfigPtr config;
+
+    /* pid file FD, ensures two copies of the driver can't use the same root */
+    int lockFD;
+
+    // All the cells created during connect open on the hypervisor.
+    virJailhouseCellInfoPtr *cell_info_list;
+};
+
+struct _jailhouseCell {
+    __s32 id;
+    char *state;
+    char *cpus_assigned_list;
+    char *cpus_failed_list;
+};
diff --git a/src/jailhouse/meson.build b/src/jailhouse/meson.build
index 45ceeecca3..a706985169 100644
--- a/src/jailhouse/meson.build
+++ b/src/jailhouse/meson.build
@@ -1,5 +1,6 @@
 jailhouse_sources = files(
   'jailhouse_driver.c',
+  'jailhouse_api.c',
 )

 driver_source_files += jailhouse_sources
diff --git a/src/libvirt.c b/src/libvirt.c
index 59b75c6f7b..b2d0ba3d23 100644
--- a/src/libvirt.c
+++ b/src/libvirt.c
@@ -75,9 +75,6 @@
 #ifdef WITH_BHYVE
 # include "bhyve/bhyve_driver.h"
 #endif
-#ifdef WITH_JAILHOUSE
-# include "jailhouse/jailhouse_driver.h"
-#endif
 #include "access/viraccessmanager.h"

 #define VIR_FROM_THIS VIR_FROM_NONE
@@ -274,10 +271,6 @@ virGlobalInit(void)
     if (hypervRegister() == -1)
         goto error;
 #endif
-#ifdef WITH_JAILHOUSE
-    if (jailhouseRegister() == -1)
-        goto error;
-#endif
 #ifdef WITH_REMOTE
     if (remoteRegister() == -1)
         goto error;
@@ -1010,9 +1003,6 @@ virConnectOpenInternal(const char *name,
 #endif
 #ifndef WITH_VZ
              STRCASEEQ(ret->uri->scheme, "parallels") ||
-#endif
-#ifndef WITH_JAILHOUSE
-             STRCASEEQ(ret->uri->scheme, "jailhouse") ||
 #endif
              false)) {
             virReportErrorHelper(VIR_FROM_NONE, VIR_ERR_CONFIG_UNSUPPORTED,
diff --git a/src/remote/remote_daemon.c b/src/remote/remote_daemon.c
index 1aa9bfc0d2..9d1b208a38 100644
--- a/src/remote/remote_daemon.c
+++ b/src/remote/remote_daemon.c
@@ -145,6 +145,10 @@ static int daemonInitialize(void)
     if (virDriverLoadModule("interface", "interfaceRegister", false) < 0)
         return -1;
 # endif
+# ifdef WITH_JAILHOUSE
+    if (virDriverLoadModule("jailhouse", "jailhouseRegister", false) < 0)
+        return -1;
+# endif
 # ifdef WITH_SECRETS
     if (virDriverLoadModule("secret", "secretRegister", false) < 0)
         return -1;
diff --git a/src/remote/remote_daemon_dispatch.c b/src/remote/remote_daemon_dispatch.c
index 53d17a8f4a..06d8fe6098 100644
--- a/src/remote/remote_daemon_dispatch.c
+++ b/src/remote/remote_daemon_dispatch.c
@@ -2115,7 +2115,8 @@ remoteDispatchConnectOpen(virNetServerPtr server G_GNUC_UNUSED,
         STREQ(type, "VBOX") ||
         STREQ(type, "bhyve") ||
         STREQ(type, "vz") ||
-        STREQ(type, "Parallels")) {
+        STREQ(type, "Parallels") ||
+        STREQ(type, "JAILHOUSE")) {
         VIR_DEBUG("Hypervisor driver found, setting URIs for secondary drivers");
         if (getuid() == 0) {
             priv->interfaceURI = "interface:///system";
--
2.17.1