Signed-off-by: Ralf Ramsauer <[email protected]>
---
Documentation/sysfs-entries.txt | 3 ++
TODO.md | 1 -
driver/main.c | 105 +++++++++++++++++++++++++++++++++++++++-
driver/main.h | 3 ++
driver/sysfs.c | 20 ++++++++
5 files changed, 130 insertions(+), 2 deletions(-)
diff --git a/Documentation/sysfs-entries.txt b/Documentation/sysfs-entries.txt
index 6b483bba..58d1f5a2 100644
--- a/Documentation/sysfs-entries.txt
+++ b/Documentation/sysfs-entries.txt
@@ -5,6 +5,7 @@ The following sysfs entries are provided by the Jailhouse Linux
driver. These
can be used for monitoring the state of the hypervisor and its cells.
/sys/devices/jailhouse
+|- console - hypervisor console (see [1])
|- 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
@@ -30,3 +31,5 @@ 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.
+
+[1] Documentation/debug-output.md
diff --git a/TODO.md b/TODO.md
index e452d306..4e93b1d7 100644
--- a/TODO.md
+++ b/TODO.md
@@ -89,7 +89,6 @@ Hardware error handling
Monitoring
- report error-triggering devices behind IOMMUs via sysfs
- - hypervisor console via debugfs?
- cell software watchdog via comm region messages
-> time out pending comm region messages and kill failing cells
(includes timeouts of unanswered shutdown requests)
diff --git a/driver/main.c b/driver/main.c
index 676794be..8a4b929f 100644
--- a/driver/main.c
+++ b/driver/main.c
@@ -19,6 +19,7 @@
#include <linux/miscdevice.h>
#include <linux/firmware.h>
#include <linux/mm.h>
+#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/uaccess.h>
#include <linux/reboot.h>
@@ -37,7 +38,6 @@
#include "pci.h"
#include "sysfs.h"
-#include <jailhouse/header.h>
#include <jailhouse/hypercall.h>
#include <generated/version.h>
@@ -77,6 +77,8 @@ static void *hypervisor_mem;
static unsigned long hv_core_and_percpu_size;
static atomic_t call_done;
static int error_code;
+static struct jailhouse_console *console_page;
+static bool console_available;
#ifdef CONFIG_X86
bool jailhouse_use_vmcall;
@@ -91,6 +93,18 @@ static void init_hypercall(void)
}
#endif
+static void copy_console_page(struct jailhouse_console *dst)
+{
+retry:
+ /* spin while hypervisor is writing to console */
+ while (console_page->lock);
+ /* copy console page */
+ memcpy(dst, console_page, sizeof(struct jailhouse_console));
+ /* check consistency of console_page */
+ if (dst->tail != console_page->tail)
+ goto retry;
+}
+
static long get_max_cpus(u32 cpu_set_size,
const struct jailhouse_system __user *system_config)
{
@@ -182,6 +196,89 @@ static inline const char * jailhouse_get_fw_name(void)
#endif
}
+static int jailhouse_console_delta(struct jailhouse_console *console,
+ char *dst, unsigned int head,
+ unsigned int *miss)
+{
+ int ret;
+ unsigned int head_mod, tail_mod;
+ unsigned int delta;
+
+ if (miss)
+ *miss = 0;
+
+ /* check if tail overflowed */
+ if (console->tail < head)
+ delta = (0 - head) + console->tail;
+ else
+ delta = console->tail - head;
+
+ /* check if we have misses */
+ if (delta > sizeof(console->content)) {
+ if (miss)
+ *miss = delta - sizeof(console->content);
+ head = console->tail - sizeof(console->content);
+ delta = sizeof(console->content);
+ }
+
+ head_mod = head % sizeof(console->content);
+ tail_mod = console->tail % sizeof(console->content);
+
+ if (head_mod + delta > sizeof(console->content)) {
+ ret = sizeof(console->content) - head_mod;
+ memcpy(dst, console->content + head_mod, ret);
+ delta -= ret;
+ memcpy(dst + ret, console->content, delta);
+ ret += delta;
+ } else {
+ ret = delta;
+ memcpy(dst, console->content + head_mod, delta);
+ }
+
+ return ret;
+}
+
+int jailhouse_console_page_delta(char *dst, unsigned int head,
+ unsigned int *miss)
+{
+ int ret;
+ struct jailhouse_console *console;
+
+ if (mutex_lock_interruptible(&jailhouse_lock) != 0)
+ return -EINTR;
+
+ if (!jailhouse_enabled) {
+ ret = -EAGAIN;
+ goto unlock_out;
+ }
+
+ if (!console_available) {
+ ret = -EPERM;
+ goto unlock_out;
+ }
+
+ console = kmalloc(sizeof(struct jailhouse_console), GFP_KERNEL);
+ if (console == NULL) {
+ ret = -ENOMEM;
+ goto unlock_out;
+ }
+
+ copy_console_page(console);
+ if (console->tail == head) {
+ ret = 0;
+ goto console_free_out;
+ }
+
+ ret = jailhouse_console_delta(console, dst, head, miss);
+
+console_free_out:
+ kfree(console);
+
+unlock_out:
+ mutex_unlock(&jailhouse_lock);
+ return ret;
+}
+
/* See Documentation/bootstrap-interface.txt */
static int jailhouse_cmd_enable(struct jailhouse_system __user *arg)
{
@@ -273,6 +370,9 @@ static int jailhouse_cmd_enable(struct jailhouse_system
__user *arg)
goto error_release_fw;
}
+ console_page = (struct jailhouse_console*)
+ (hypervisor_mem + header->console_page);
+
/* Copy hypervisor's binary image at beginning of the memory region
* and clear the rest to zero. */
memcpy(hypervisor_mem, hypervisor->data, hypervisor->size);
@@ -329,6 +429,9 @@ static int jailhouse_cmd_enable(struct jailhouse_system
__user *arg)
}
#endif
+ console_available = CON2_TYPE(config->debug_console.flags) ==
+ JAILHOUSE_CON2_TYPE_ROOTPAGE;
+
err = jailhouse_cell_prepare_root(&config->root_cell);
if (err)
goto error_unmap;
diff --git a/driver/main.h b/driver/main.h
index e01ca5b5..8a92c59e 100644
--- a/driver/main.h
+++ b/driver/main.h
@@ -14,6 +14,7 @@
#define _JAILHOUSE_DRIVER_MAIN_H
#include <linux/mutex.h>
+#include <jailhouse/header.h>
#include "cell.h"
@@ -22,5 +23,7 @@ extern bool jailhouse_enabled;
void *jailhouse_ioremap(phys_addr_t phys, unsigned long virt,
unsigned long size);
+int jailhouse_console_page_delta(char *dst, unsigned int head,
+ unsigned int *miss);
#endif /* !_JAILHOUSE_DRIVER_MAIN_H */
diff --git a/driver/sysfs.c b/driver/sysfs.c
index 8da1f766..08c15d6d 100644
--- a/driver/sysfs.c
+++ b/driver/sysfs.c
@@ -309,6 +309,24 @@ void jailhouse_sysfs_cell_delete(struct cell *cell)
kobject_put(&cell->kobj);
}
+static ssize_t console_show(struct device *dev, struct device_attribute *attr,
+ char *buffer)
+{
+ ssize_t ret;
+
+ ret = jailhouse_console_page_delta(buffer, 0, NULL);
+ if (ret > 0)
+ /* We can safely fill the whole buffer and append a terminating
+ * \0, as buffer comes preallocated with PAGE_SIZE and
+ * the content is smaller than PAGE_SIZE */
+ buffer[ret++] = 0;
+
+ /* don't return error if jailhouse is not enabled */
+ if (ret == -EAGAIN)
+ ret = 0;
+ return ret;
+}
+
static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
char *buffer)
{
@@ -361,6 +379,7 @@ static ssize_t remap_pool_used_show(struct device *dev,
return info_show(dev, buffer, JAILHOUSE_INFO_REMAP_POOL_USED);
}
+static DEVICE_ATTR_RO(console);
static DEVICE_ATTR_RO(enabled);
static DEVICE_ATTR_RO(mem_pool_size);
static DEVICE_ATTR_RO(mem_pool_used);
@@ -368,6 +387,7 @@ static DEVICE_ATTR_RO(remap_pool_size);
static DEVICE_ATTR_RO(remap_pool_used);
static struct attribute *jailhouse_sysfs_entries[] = {
+ &dev_attr_console.attr,
&dev_attr_enabled.attr,
&dev_attr_mem_pool_size.attr,
&dev_attr_mem_pool_used.attr,
--
2.11.0
--
You received this message because you are subscribed to the Google Groups
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.