]> rtime.felk.cvut.cz Git - jailhouse.git/commitdiff
driver: Factor out sysfs module
authorJan Kiszka <jan.kiszka@siemens.com>
Mon, 9 Mar 2015 10:00:47 +0000 (11:00 +0100)
committerJan Kiszka <jan.kiszka@siemens.com>
Fri, 20 Mar 2015 06:10:39 +0000 (07:10 +0100)
Push all functions that build and serve the driver's sysfs view into a
separate module. This reduces the size of main.c significantly and makes
it more readable again.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
driver/Makefile
driver/main.c
driver/main.h
driver/sysfs.c [new file with mode: 0644]
driver/sysfs.h [new file with mode: 0644]

index d33112d623d743d40e42087066a150e387941723..fc231dab75951071a6bc2ffc9fac9dc7faaae53a 100644 (file)
@@ -16,7 +16,7 @@ obj-m := jailhouse.o
 ccflags-y := -I$(src)/../hypervisor/arch/$(SRCARCH)/include \
             -I$(src)/../hypervisor/include
 
-jailhouse-y := main.o
+jailhouse-y := main.o sysfs.o
 jailhouse-$(CONFIG_PCI) += pci.o
 
 $(obj)/main.o: $(obj)/../hypervisor/include/generated/version.h
index 0983c661cb60f0642b0b66fd5830323f86e36011..8f3796c9f14e5f12c2bf950557b9d5f8178ec10a 100644 (file)
@@ -34,6 +34,7 @@
 #include "jailhouse.h"
 #include "main.h"
 #include "pci.h"
+#include "sysfs.h"
 
 #include <jailhouse/header.h>
 #include <jailhouse/hypercall.h>
 /* For compatibility with older kernel versions */
 #include <linux/version.h>
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
-#define DEVICE_ATTR_RO(_name) \
-       struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
-#endif /* < 3.11 */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
-static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
-                             char *buf)
-{
-       struct kobj_attribute *kattr;
-       ssize_t ret = -EIO;
-
-       kattr = container_of(attr, struct kobj_attribute, attr);
-       if (kattr->show)
-               ret = kattr->show(kobj, kattr, buf);
-       return ret;
-}
-
-static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,
-                              const char *buf, size_t count)
-{
-       struct kobj_attribute *kattr;
-       ssize_t ret = -EIO;
-
-       kattr = container_of(attr, struct kobj_attribute, attr);
-       if (kattr->store)
-               ret = kattr->store(kobj, kattr, buf, count);
-       return ret;
-}
-
-static const struct sysfs_ops cell_sysfs_ops = {
-       .show   = kobj_attr_show,
-       .store  = kobj_attr_store,
-};
-#define kobj_sysfs_ops cell_sysfs_ops
-#endif /* < 3.14 */
-/* End of compatibility section - remove as version become obsolete */
-
 #ifdef CONFIG_X86
 #define JAILHOUSE_AMD_FW_NAME  "jailhouse-amd.bin"
 #define JAILHOUSE_INTEL_FW_NAME        "jailhouse-intel.bin"
@@ -116,7 +79,6 @@ static atomic_t call_done;
 static int error_code;
 static LIST_HEAD(cells);
 static struct cell *root_cell;
-static struct kobject *cells_dir;
 
 #ifdef CONFIG_X86
 bool jailhouse_use_vmcall;
@@ -131,170 +93,7 @@ static void init_hypercall(void)
 }
 #endif
 
-struct jailhouse_cpu_stats_attr {
-       struct kobj_attribute kattr;
-       unsigned int code;
-};
-
-static ssize_t stats_show(struct kobject *kobj, struct kobj_attribute *attr,
-                         char *buffer)
-{
-       struct jailhouse_cpu_stats_attr *stats_attr =
-               container_of(attr, struct jailhouse_cpu_stats_attr, kattr);
-       unsigned int code = JAILHOUSE_CPU_INFO_STAT_BASE + stats_attr->code;
-       struct cell *cell = container_of(kobj, struct cell, kobj);
-       unsigned long sum = 0;
-       unsigned int cpu;
-       int value;
-
-       for_each_cpu(cpu, &cell->cpus_assigned) {
-               value = jailhouse_call_arg2(JAILHOUSE_HC_CPU_GET_INFO, cpu,
-                                           code);
-               if (value > 0)
-                       sum += value;
-       }
-
-       return sprintf(buffer, "%lu\n", sum);
-}
-
-#define JAILHOUSE_CPU_STATS_ATTR(_name, _code) \
-       static struct jailhouse_cpu_stats_attr _name##_attr = { \
-               .kattr = __ATTR(_name, S_IRUGO, stats_show, NULL), \
-               .code = _code, \
-       }
-
-JAILHOUSE_CPU_STATS_ATTR(vmexits_total, JAILHOUSE_CPU_STAT_VMEXITS_TOTAL);
-JAILHOUSE_CPU_STATS_ATTR(vmexits_mmio, JAILHOUSE_CPU_STAT_VMEXITS_MMIO);
-JAILHOUSE_CPU_STATS_ATTR(vmexits_management,
-                        JAILHOUSE_CPU_STAT_VMEXITS_MANAGEMENT);
-JAILHOUSE_CPU_STATS_ATTR(vmexits_hypercall,
-                        JAILHOUSE_CPU_STAT_VMEXITS_HYPERCALL);
-#ifdef CONFIG_X86
-JAILHOUSE_CPU_STATS_ATTR(vmexits_pio, JAILHOUSE_CPU_STAT_VMEXITS_PIO);
-JAILHOUSE_CPU_STATS_ATTR(vmexits_xapic, JAILHOUSE_CPU_STAT_VMEXITS_XAPIC);
-JAILHOUSE_CPU_STATS_ATTR(vmexits_cr, JAILHOUSE_CPU_STAT_VMEXITS_CR);
-JAILHOUSE_CPU_STATS_ATTR(vmexits_msr, JAILHOUSE_CPU_STAT_VMEXITS_MSR);
-JAILHOUSE_CPU_STATS_ATTR(vmexits_cpuid, JAILHOUSE_CPU_STAT_VMEXITS_CPUID);
-JAILHOUSE_CPU_STATS_ATTR(vmexits_xsetbv, JAILHOUSE_CPU_STAT_VMEXITS_XSETBV);
-#elif defined(CONFIG_ARM)
-JAILHOUSE_CPU_STATS_ATTR(vmexits_maintenance, JAILHOUSE_CPU_STAT_VMEXITS_MAINTENANCE);
-JAILHOUSE_CPU_STATS_ATTR(vmexits_virt_irq, JAILHOUSE_CPU_STAT_VMEXITS_VIRQ);
-JAILHOUSE_CPU_STATS_ATTR(vmexits_virt_sgi, JAILHOUSE_CPU_STAT_VMEXITS_VSGI);
-#endif
-
-static struct attribute *no_attrs[] = {
-       &vmexits_total_attr.kattr.attr,
-       &vmexits_mmio_attr.kattr.attr,
-       &vmexits_management_attr.kattr.attr,
-       &vmexits_hypercall_attr.kattr.attr,
-#ifdef CONFIG_X86
-       &vmexits_pio_attr.kattr.attr,
-       &vmexits_xapic_attr.kattr.attr,
-       &vmexits_cr_attr.kattr.attr,
-       &vmexits_msr_attr.kattr.attr,
-       &vmexits_cpuid_attr.kattr.attr,
-       &vmexits_xsetbv_attr.kattr.attr,
-#elif defined(CONFIG_ARM)
-       &vmexits_maintenance_attr.kattr.attr,
-       &vmexits_virt_irq_attr.kattr.attr,
-       &vmexits_virt_sgi_attr.kattr.attr,
-#endif
-       NULL
-};
-
-static struct attribute_group stats_attr_group = {
-       .attrs = no_attrs,
-       .name = "statistics"
-};
-
-static ssize_t id_show(struct kobject *kobj, struct kobj_attribute *attr,
-                      char *buffer)
-{
-       struct cell *cell = container_of(kobj, struct cell, kobj);
-
-       return sprintf(buffer, "%u\n", cell->id);
-}
-
-static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
-                         char *buffer)
-{
-       struct cell *cell = container_of(kobj, struct cell, kobj);
-
-       switch (jailhouse_call_arg1(JAILHOUSE_HC_CELL_GET_STATE, cell->id)) {
-       case JAILHOUSE_CELL_RUNNING:
-               return sprintf(buffer, "running\n");
-       case JAILHOUSE_CELL_RUNNING_LOCKED:
-               return sprintf(buffer, "running/locked\n");
-       case JAILHOUSE_CELL_SHUT_DOWN:
-               return sprintf(buffer, "shut down\n");
-       case JAILHOUSE_CELL_FAILED:
-               return sprintf(buffer, "failed\n");
-       default:
-               return sprintf(buffer, "invalid\n");
-       }
-}
-
-static ssize_t cpus_assigned_show(struct kobject *kobj,
-                                 struct kobj_attribute *attr, char *buf)
-{
-       struct cell *cell = container_of(kobj, struct cell, kobj);
-       int written;
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
-       written = scnprintf(buf, PAGE_SIZE, "%*pb\n",
-                           cpumask_pr_args(&cell->cpus_assigned));
-#else
-       written = cpumask_scnprintf(buf, PAGE_SIZE, &cell->cpus_assigned);
-       written += scnprintf(buf + written, PAGE_SIZE - written, "\n");
-#endif
-       return written;
-}
-
-static ssize_t cpus_failed_show(struct kobject *kobj,
-                               struct kobj_attribute *attr, char *buf)
-{
-       struct cell *cell = container_of(kobj, struct cell, kobj);
-       cpumask_var_t cpus_failed;
-       unsigned int cpu;
-       int written;
-
-       if (!zalloc_cpumask_var(&cpus_failed, GFP_KERNEL))
-               return -ENOMEM;
-
-       for_each_cpu(cpu, &cell->cpus_assigned)
-               if (jailhouse_call_arg2(JAILHOUSE_HC_CPU_GET_INFO, cpu,
-                                       JAILHOUSE_CPU_INFO_STATE) ==
-                   JAILHOUSE_CPU_FAILED)
-                       cpu_set(cpu, *cpus_failed);
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
-       written = scnprintf(buf, PAGE_SIZE, "%*pb\n",
-                           cpumask_pr_args(cpus_failed));
-#else
-       written = cpumask_scnprintf(buf, PAGE_SIZE, cpus_failed);
-       written += scnprintf(buf + written, PAGE_SIZE - written, "\n");
-#endif
-
-       free_cpumask_var(cpus_failed);
-
-       return written;
-}
-
-static struct kobj_attribute cell_id_attr = __ATTR_RO(id);
-static struct kobj_attribute cell_state_attr = __ATTR_RO(state);
-static struct kobj_attribute cell_cpus_assigned_attr =
-       __ATTR_RO(cpus_assigned);
-static struct kobj_attribute cell_cpus_failed_attr = __ATTR_RO(cpus_failed);
-
-static struct attribute *cell_attrs[] = {
-       &cell_id_attr.attr,
-       &cell_state_attr.attr,
-       &cell_cpus_assigned_attr.attr,
-       &cell_cpus_failed_attr.attr,
-       NULL,
-};
-
-static void cell_kobj_release(struct kobject *kobj)
+void jailhouse_cell_kobj_release(struct kobject *kobj)
 {
        struct cell *cell = container_of(kobj, struct cell, kobj);
 
@@ -303,12 +102,6 @@ static void cell_kobj_release(struct kobject *kobj)
        kfree(cell);
 }
 
-static struct kobj_type cell_type = {
-       .release = cell_kobj_release,
-       .sysfs_ops = &kobj_sysfs_ops,
-       .default_attrs = cell_attrs,
-};
-
 static struct cell *create_cell(const struct jailhouse_cell_desc *cell_desc)
 {
        struct cell *cell;
@@ -342,18 +135,10 @@ static struct cell *create_cell(const struct jailhouse_cell_desc *cell_desc)
                return ERR_PTR(err);
        }
 
-       err = kobject_init_and_add(&cell->kobj, &cell_type, cells_dir, "%s",
-                                  cell_desc->name);
-       if (err) {
-               cell_kobj_release(&cell->kobj);
+       err = jailhouse_sysfs_cell_create(cell, cell_desc->name);
+       if (err)
+               /* cleanup done by jailhouse_sysfs_cell_create */
                return ERR_PTR(err);
-       }
-
-       err = sysfs_create_group(&cell->kobj, &stats_attr_group);
-       if (err) {
-               kobject_put(&cell->kobj);
-               return ERR_PTR(err);
-       }
 
        return cell;
 }
@@ -361,7 +146,7 @@ static struct cell *create_cell(const struct jailhouse_cell_desc *cell_desc)
 static void register_cell(struct cell *cell)
 {
        list_add_tail(&cell->entry, &cells);
-       kobject_uevent(&cell->kobj, KOBJ_ADD);
+       jailhouse_sysfs_cell_register(cell);
 }
 
 static struct cell *find_cell(struct jailhouse_cell_id *cell_id)
@@ -379,8 +164,7 @@ static struct cell *find_cell(struct jailhouse_cell_id *cell_id)
 static void delete_cell(struct cell *cell)
 {
        list_del(&cell->entry);
-       sysfs_remove_group(&cell->kobj, &stats_attr_group);
-       kobject_put(&cell->kobj);
+       jailhouse_sysfs_cell_delete(cell);
 }
 
 static long get_max_cpus(u32 cpu_set_size,
@@ -1015,78 +799,6 @@ static struct notifier_block jailhouse_shutdown_nb = {
        .notifier_call = jailhouse_shutdown_notify,
 };
 
-static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
-                           char *buffer)
-{
-       return sprintf(buffer, "%d\n", jailhouse_enabled);
-}
-
-static ssize_t info_show(struct device *dev, char *buffer, unsigned int type)
-{
-       ssize_t result;
-       long val = 0;
-
-       if (mutex_lock_interruptible(&jailhouse_lock) != 0)
-               return -EINTR;
-
-       if (jailhouse_enabled)
-               val = jailhouse_call_arg1(JAILHOUSE_HC_HYPERVISOR_GET_INFO,
-                                         type);
-       if (val >= 0)
-               result = sprintf(buffer, "%ld\n", val);
-       else
-               result = val;
-
-       mutex_unlock(&jailhouse_lock);
-       return result;
-}
-
-static ssize_t mem_pool_size_show(struct device *dev,
-                                 struct device_attribute *attr, char *buffer)
-{
-       return info_show(dev, buffer, JAILHOUSE_INFO_MEM_POOL_SIZE);
-}
-
-static ssize_t mem_pool_used_show(struct device *dev,
-                                 struct device_attribute *attr, char *buffer)
-{
-       return info_show(dev, buffer, JAILHOUSE_INFO_MEM_POOL_USED);
-}
-
-static ssize_t remap_pool_size_show(struct device *dev,
-                                   struct device_attribute *attr,
-                                   char *buffer)
-{
-       return info_show(dev, buffer, JAILHOUSE_INFO_REMAP_POOL_SIZE);
-}
-
-static ssize_t remap_pool_used_show(struct device *dev,
-                                   struct device_attribute *attr,
-                                   char *buffer)
-{
-       return info_show(dev, buffer, JAILHOUSE_INFO_REMAP_POOL_USED);
-}
-
-static DEVICE_ATTR_RO(enabled);
-static DEVICE_ATTR_RO(mem_pool_size);
-static DEVICE_ATTR_RO(mem_pool_used);
-static DEVICE_ATTR_RO(remap_pool_size);
-static DEVICE_ATTR_RO(remap_pool_used);
-
-static struct attribute *jailhouse_sysfs_entries[] = {
-       &dev_attr_enabled.attr,
-       &dev_attr_mem_pool_size.attr,
-       &dev_attr_mem_pool_used.attr,
-       &dev_attr_remap_pool_size.attr,
-       &dev_attr_remap_pool_used.attr,
-       NULL
-};
-
-static struct attribute_group jailhouse_attribute_group = {
-       .name = NULL,
-       .attrs = jailhouse_sysfs_entries,
-};
-
 static int __init jailhouse_init(void)
 {
        int err;
@@ -1095,20 +807,13 @@ static int __init jailhouse_init(void)
        if (IS_ERR(jailhouse_dev))
                return PTR_ERR(jailhouse_dev);
 
-       err = sysfs_create_group(&jailhouse_dev->kobj,
-                                &jailhouse_attribute_group);
+       err = jailhouse_sysfs_init(jailhouse_dev);
        if (err)
                goto unreg_dev;
 
-       cells_dir = kobject_create_and_add("cells", &jailhouse_dev->kobj);
-       if (!cells_dir) {
-               err = -ENOMEM;
-               goto remove_attrs;
-       }
-
        err = misc_register(&jailhouse_misc_dev);
        if (err)
-               goto remove_cells_dir;
+               goto exit_sysfs;
 
        register_reboot_notifier(&jailhouse_shutdown_nb);
 
@@ -1116,11 +821,8 @@ static int __init jailhouse_init(void)
 
        return 0;
 
-remove_cells_dir:
-       kobject_put(cells_dir);
-
-remove_attrs:
-       sysfs_remove_group(&jailhouse_dev->kobj, &jailhouse_attribute_group);
+exit_sysfs:
+       jailhouse_sysfs_exit(jailhouse_dev);
 
 unreg_dev:
        root_device_unregister(jailhouse_dev);
@@ -1131,8 +833,7 @@ static void __exit jailhouse_exit(void)
 {
        unregister_reboot_notifier(&jailhouse_shutdown_nb);
        misc_deregister(&jailhouse_misc_dev);
-       kobject_put(cells_dir);
-       sysfs_remove_group(&jailhouse_dev->kobj, &jailhouse_attribute_group);
+       jailhouse_sysfs_exit(jailhouse_dev);
        root_device_unregister(jailhouse_dev);
 }
 
index ae727ec90dbef2c920dc47945328bbbae2aca988..9b262e904c9206502602eb43b73011e83e8c9116 100644 (file)
@@ -18,4 +18,6 @@
 extern struct mutex jailhouse_lock;
 extern bool jailhouse_enabled;
 
+void jailhouse_cell_kobj_release(struct kobject *kobj);
+
 #endif /* !_JAILHOUSE_DRIVER_MAIN_H */
diff --git a/driver/sysfs.c b/driver/sysfs.c
new file mode 100644 (file)
index 0000000..52b460e
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) Siemens AG, 2014-2015
+ *
+ * Authors:
+ *  Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include "cell.h"
+#include "jailhouse.h"
+#include "main.h"
+#include "sysfs.h"
+
+#include <jailhouse/hypercall.h>
+
+/* For compatibility with older kernel versions */
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
+#define DEVICE_ATTR_RO(_name) \
+       struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
+#endif /* < 3.11 */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
+static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
+                             char *buf)
+{
+       struct kobj_attribute *kattr;
+       ssize_t ret = -EIO;
+
+       kattr = container_of(attr, struct kobj_attribute, attr);
+       if (kattr->show)
+               ret = kattr->show(kobj, kattr, buf);
+       return ret;
+}
+
+static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,
+                              const char *buf, size_t count)
+{
+       struct kobj_attribute *kattr;
+       ssize_t ret = -EIO;
+
+       kattr = container_of(attr, struct kobj_attribute, attr);
+       if (kattr->store)
+               ret = kattr->store(kobj, kattr, buf, count);
+       return ret;
+}
+
+static const struct sysfs_ops cell_sysfs_ops = {
+       .show   = kobj_attr_show,
+       .store  = kobj_attr_store,
+};
+#define kobj_sysfs_ops cell_sysfs_ops
+#endif /* < 3.14 */
+/* End of compatibility section - remove as version become obsolete */
+
+static struct kobject *cells_dir;
+
+struct jailhouse_cpu_stats_attr {
+       struct kobj_attribute kattr;
+       unsigned int code;
+};
+
+static ssize_t stats_show(struct kobject *kobj, struct kobj_attribute *attr,
+                         char *buffer)
+{
+       struct jailhouse_cpu_stats_attr *stats_attr =
+               container_of(attr, struct jailhouse_cpu_stats_attr, kattr);
+       unsigned int code = JAILHOUSE_CPU_INFO_STAT_BASE + stats_attr->code;
+       struct cell *cell = container_of(kobj, struct cell, kobj);
+       unsigned long sum = 0;
+       unsigned int cpu;
+       int value;
+
+       for_each_cpu(cpu, &cell->cpus_assigned) {
+               value = jailhouse_call_arg2(JAILHOUSE_HC_CPU_GET_INFO, cpu,
+                                           code);
+               if (value > 0)
+                       sum += value;
+       }
+
+       return sprintf(buffer, "%lu\n", sum);
+}
+
+#define JAILHOUSE_CPU_STATS_ATTR(_name, _code) \
+       static struct jailhouse_cpu_stats_attr _name##_attr = { \
+               .kattr = __ATTR(_name, S_IRUGO, stats_show, NULL), \
+               .code = _code, \
+       }
+
+JAILHOUSE_CPU_STATS_ATTR(vmexits_total, JAILHOUSE_CPU_STAT_VMEXITS_TOTAL);
+JAILHOUSE_CPU_STATS_ATTR(vmexits_mmio, JAILHOUSE_CPU_STAT_VMEXITS_MMIO);
+JAILHOUSE_CPU_STATS_ATTR(vmexits_management,
+                        JAILHOUSE_CPU_STAT_VMEXITS_MANAGEMENT);
+JAILHOUSE_CPU_STATS_ATTR(vmexits_hypercall,
+                        JAILHOUSE_CPU_STAT_VMEXITS_HYPERCALL);
+#ifdef CONFIG_X86
+JAILHOUSE_CPU_STATS_ATTR(vmexits_pio, JAILHOUSE_CPU_STAT_VMEXITS_PIO);
+JAILHOUSE_CPU_STATS_ATTR(vmexits_xapic, JAILHOUSE_CPU_STAT_VMEXITS_XAPIC);
+JAILHOUSE_CPU_STATS_ATTR(vmexits_cr, JAILHOUSE_CPU_STAT_VMEXITS_CR);
+JAILHOUSE_CPU_STATS_ATTR(vmexits_msr, JAILHOUSE_CPU_STAT_VMEXITS_MSR);
+JAILHOUSE_CPU_STATS_ATTR(vmexits_cpuid, JAILHOUSE_CPU_STAT_VMEXITS_CPUID);
+JAILHOUSE_CPU_STATS_ATTR(vmexits_xsetbv, JAILHOUSE_CPU_STAT_VMEXITS_XSETBV);
+#elif defined(CONFIG_ARM)
+JAILHOUSE_CPU_STATS_ATTR(vmexits_maintenance, JAILHOUSE_CPU_STAT_VMEXITS_MAINTENANCE);
+JAILHOUSE_CPU_STATS_ATTR(vmexits_virt_irq, JAILHOUSE_CPU_STAT_VMEXITS_VIRQ);
+JAILHOUSE_CPU_STATS_ATTR(vmexits_virt_sgi, JAILHOUSE_CPU_STAT_VMEXITS_VSGI);
+#endif
+
+static struct attribute *no_attrs[] = {
+       &vmexits_total_attr.kattr.attr,
+       &vmexits_mmio_attr.kattr.attr,
+       &vmexits_management_attr.kattr.attr,
+       &vmexits_hypercall_attr.kattr.attr,
+#ifdef CONFIG_X86
+       &vmexits_pio_attr.kattr.attr,
+       &vmexits_xapic_attr.kattr.attr,
+       &vmexits_cr_attr.kattr.attr,
+       &vmexits_msr_attr.kattr.attr,
+       &vmexits_cpuid_attr.kattr.attr,
+       &vmexits_xsetbv_attr.kattr.attr,
+#elif defined(CONFIG_ARM)
+       &vmexits_maintenance_attr.kattr.attr,
+       &vmexits_virt_irq_attr.kattr.attr,
+       &vmexits_virt_sgi_attr.kattr.attr,
+#endif
+       NULL
+};
+
+static struct attribute_group stats_attr_group = {
+       .attrs = no_attrs,
+       .name = "statistics"
+};
+
+static ssize_t id_show(struct kobject *kobj, struct kobj_attribute *attr,
+                      char *buffer)
+{
+       struct cell *cell = container_of(kobj, struct cell, kobj);
+
+       return sprintf(buffer, "%u\n", cell->id);
+}
+
+static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
+                         char *buffer)
+{
+       struct cell *cell = container_of(kobj, struct cell, kobj);
+
+       switch (jailhouse_call_arg1(JAILHOUSE_HC_CELL_GET_STATE, cell->id)) {
+       case JAILHOUSE_CELL_RUNNING:
+               return sprintf(buffer, "running\n");
+       case JAILHOUSE_CELL_RUNNING_LOCKED:
+               return sprintf(buffer, "running/locked\n");
+       case JAILHOUSE_CELL_SHUT_DOWN:
+               return sprintf(buffer, "shut down\n");
+       case JAILHOUSE_CELL_FAILED:
+               return sprintf(buffer, "failed\n");
+       default:
+               return sprintf(buffer, "invalid\n");
+       }
+}
+
+static ssize_t cpus_assigned_show(struct kobject *kobj,
+                                 struct kobj_attribute *attr, char *buf)
+{
+       struct cell *cell = container_of(kobj, struct cell, kobj);
+       int written;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
+       written = scnprintf(buf, PAGE_SIZE, "%*pb\n",
+                           cpumask_pr_args(&cell->cpus_assigned));
+#else
+       written = cpumask_scnprintf(buf, PAGE_SIZE, &cell->cpus_assigned);
+       written += scnprintf(buf + written, PAGE_SIZE - written, "\n");
+#endif
+       return written;
+}
+
+static ssize_t cpus_failed_show(struct kobject *kobj,
+                               struct kobj_attribute *attr, char *buf)
+{
+       struct cell *cell = container_of(kobj, struct cell, kobj);
+       cpumask_var_t cpus_failed;
+       unsigned int cpu;
+       int written;
+
+       if (!zalloc_cpumask_var(&cpus_failed, GFP_KERNEL))
+               return -ENOMEM;
+
+       for_each_cpu(cpu, &cell->cpus_assigned)
+               if (jailhouse_call_arg2(JAILHOUSE_HC_CPU_GET_INFO, cpu,
+                                       JAILHOUSE_CPU_INFO_STATE) ==
+                   JAILHOUSE_CPU_FAILED)
+                       cpu_set(cpu, *cpus_failed);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
+       written = scnprintf(buf, PAGE_SIZE, "%*pb\n",
+                           cpumask_pr_args(cpus_failed));
+#else
+       written = cpumask_scnprintf(buf, PAGE_SIZE, cpus_failed);
+       written += scnprintf(buf + written, PAGE_SIZE - written, "\n");
+#endif
+
+       free_cpumask_var(cpus_failed);
+
+       return written;
+}
+
+static struct kobj_attribute cell_id_attr = __ATTR_RO(id);
+static struct kobj_attribute cell_state_attr = __ATTR_RO(state);
+static struct kobj_attribute cell_cpus_assigned_attr =
+       __ATTR_RO(cpus_assigned);
+static struct kobj_attribute cell_cpus_failed_attr = __ATTR_RO(cpus_failed);
+
+static struct attribute *cell_attrs[] = {
+       &cell_id_attr.attr,
+       &cell_state_attr.attr,
+       &cell_cpus_assigned_attr.attr,
+       &cell_cpus_failed_attr.attr,
+       NULL,
+};
+
+static struct kobj_type cell_type = {
+       .release = jailhouse_cell_kobj_release,
+       .sysfs_ops = &kobj_sysfs_ops,
+       .default_attrs = cell_attrs,
+};
+
+int jailhouse_sysfs_cell_create(struct cell *cell, const char *name)
+{
+       int err;
+
+       err = kobject_init_and_add(&cell->kobj, &cell_type, cells_dir, "%s",
+                                  name);
+       if (err) {
+               jailhouse_cell_kobj_release(&cell->kobj);
+               return err;
+       }
+
+       err = sysfs_create_group(&cell->kobj, &stats_attr_group);
+       if (err) {
+               kobject_put(&cell->kobj);
+               return err;
+       }
+
+       return 0;
+}
+
+void jailhouse_sysfs_cell_register(struct cell *cell)
+{
+       kobject_uevent(&cell->kobj, KOBJ_ADD);
+}
+
+void jailhouse_sysfs_cell_delete(struct cell *cell)
+{
+       sysfs_remove_group(&cell->kobj, &stats_attr_group);
+       kobject_put(&cell->kobj);
+}
+
+static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
+                           char *buffer)
+{
+       return sprintf(buffer, "%d\n", jailhouse_enabled);
+}
+
+static ssize_t info_show(struct device *dev, char *buffer, unsigned int type)
+{
+       ssize_t result;
+       long val = 0;
+
+       if (mutex_lock_interruptible(&jailhouse_lock) != 0)
+               return -EINTR;
+
+       if (jailhouse_enabled)
+               val = jailhouse_call_arg1(JAILHOUSE_HC_HYPERVISOR_GET_INFO,
+                                         type);
+       if (val >= 0)
+               result = sprintf(buffer, "%ld\n", val);
+       else
+               result = val;
+
+       mutex_unlock(&jailhouse_lock);
+       return result;
+}
+
+static ssize_t mem_pool_size_show(struct device *dev,
+                                 struct device_attribute *attr, char *buffer)
+{
+       return info_show(dev, buffer, JAILHOUSE_INFO_MEM_POOL_SIZE);
+}
+
+static ssize_t mem_pool_used_show(struct device *dev,
+                                 struct device_attribute *attr, char *buffer)
+{
+       return info_show(dev, buffer, JAILHOUSE_INFO_MEM_POOL_USED);
+}
+
+static ssize_t remap_pool_size_show(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buffer)
+{
+       return info_show(dev, buffer, JAILHOUSE_INFO_REMAP_POOL_SIZE);
+}
+
+static ssize_t remap_pool_used_show(struct device *dev,
+                                   struct device_attribute *attr,
+                                   char *buffer)
+{
+       return info_show(dev, buffer, JAILHOUSE_INFO_REMAP_POOL_USED);
+}
+
+static DEVICE_ATTR_RO(enabled);
+static DEVICE_ATTR_RO(mem_pool_size);
+static DEVICE_ATTR_RO(mem_pool_used);
+static DEVICE_ATTR_RO(remap_pool_size);
+static DEVICE_ATTR_RO(remap_pool_used);
+
+static struct attribute *jailhouse_sysfs_entries[] = {
+       &dev_attr_enabled.attr,
+       &dev_attr_mem_pool_size.attr,
+       &dev_attr_mem_pool_used.attr,
+       &dev_attr_remap_pool_size.attr,
+       &dev_attr_remap_pool_used.attr,
+       NULL
+};
+
+static struct attribute_group jailhouse_attribute_group = {
+       .name = NULL,
+       .attrs = jailhouse_sysfs_entries,
+};
+
+int jailhouse_sysfs_init(struct device *dev)
+{
+       int err;
+
+       err = sysfs_create_group(&dev->kobj, &jailhouse_attribute_group);
+       if (err)
+               return err;
+
+       cells_dir = kobject_create_and_add("cells", &dev->kobj);
+       if (!cells_dir) {
+               sysfs_remove_group(&dev->kobj, &jailhouse_attribute_group);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+void jailhouse_sysfs_exit(struct device *dev)
+{
+       kobject_put(cells_dir);
+       sysfs_remove_group(&dev->kobj, &jailhouse_attribute_group);
+}
diff --git a/driver/sysfs.h b/driver/sysfs.h
new file mode 100644 (file)
index 0000000..ad0e2f9
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) Siemens AG, 2014-2015
+ *
+ * Authors:
+ *  Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef _JAILHOUSE_DRIVER_SYSFS_H
+#define _JAILHOUSE_DRIVER_SYSFS_H
+
+#include <linux/device.h>
+
+int jailhouse_sysfs_cell_create(struct cell *cell, const char *name);
+void jailhouse_sysfs_cell_register(struct cell *cell);
+void jailhouse_sysfs_cell_delete(struct cell *cell);
+
+int jailhouse_sysfs_init(struct device *dev);
+void jailhouse_sysfs_exit(struct device *dev);
+
+#endif /* !_JAILHOUSE_DRIVER_SYSFS_H */