can be used for monitoring the state of the hypervisor and its cells.
/sys/devices/jailhouse
-|-- enabled - 1 if Jailhouse is enabled, 0 otherwise
-|-- mem_pool_size - number of pages in hypervisor memory pool
-|-- mem_pool_used - used pages of hypervisor memory pool
-|-- remap_pool_size - number of pages in hypervisor remapping pool
-|-- remap_pool_used - used pages of hypervisor remapping pool
-`-- cells
- |-- <name of cell>
- | |-- id - unique numerical ID
- | |-- state - "running", "shut down", or "failed"
- | |-- cpus_assigned - bitmask of assigned logical CPUs
- | `-- cpus_failed - bitmask of logical CPUs that caused a failure
- `-- ...
+|- enabled - 1 if Jailhouse is enabled, 0 otherwise
+|- mem_pool_size - number of pages in hypervisor memory pool
+|- mem_pool_used - used pages of hypervisor memory pool
+|- remap_pool_size - number of pages in hypervisor remapping pool
+|- remap_pool_used - used pages of hypervisor remapping pool
+`- cells
+ |- <name of cell>
+ | |- id - unique numerical ID
+ | |- state - "running", "shut down", or "failed"
+ | |- cpus_assigned - bitmask of assigned logical CPUs
+ | |- cpus_failed - bitmask of logical CPUs that caused a failure
+ | `- statistics
+ | |- vmexits_total - Total number of VM exits
+ | `- vmexits_<reason> - VM exits due to <reason>
+ `- ...
+
+Note that statistics are accumulated non-atomically over all CPUs of a cell and
+may not reflect a fully consistent state. The existence and semantics of VM
+exit reason values are architecture-dependent and may change in future
+versions. In general statistics shall only be considered as a first hint when
+analyzing cell behavior.
#define MIN(a, b) ((a) < (b) ? (a) : (b))
+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 int cpu, value;
+ unsigned long sum = 0;
+
+ 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);
+#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,
+#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)
{
if (!cell)
return ERR_PTR(-ENOMEM);
+ INIT_LIST_HEAD(&cell->entry);
+
bitmap_copy(cpumask_bits(&cell->cpus_assigned),
jailhouse_cell_cpu_set(cell_desc),
MIN(nr_cpumask_bits, cell_desc->cpu_set_size * 8));
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;
}
static void delete_cell(struct cell *cell)
{
list_del(&cell->entry);
+ sysfs_remove_group(&cell->kobj, &stats_attr_group);
kobject_put(&cell->kobj);
}
return 0;
error_free_cell:
- kobject_put(&root_cell->kobj);
+ delete_cell(root_cell);
error_unmap:
vunmap(hypervisor_mem);
if (!cpumask_subset(&cell->cpus_assigned, &root_cell->cpus_assigned)) {
err = -EBUSY;
- goto error_cell_put;
+ goto error_cell_delete;
}
for_each_cpu(cpu, &cell->cpus_assigned) {
cpu_set(cpu, root_cell->cpus_assigned);
}
-error_cell_put:
- kobject_put(&cell->kobj);
+error_cell_delete:
+ delete_cell(cell);
goto unlock_out;
}