On 2017-01-19 21:11, Ralf Ramsauer wrote:
> Signed-off-by: Ralf Ramsauer <[email protected]>
> ---
>  Documentation/sysfs-entries.txt |  3 ++
>  TODO.md                         |  1 -
>  driver/main.c                   | 98 
> +++++++++++++++++++++++++++++++++++++++++
>  driver/main.h                   |  2 +
>  driver/sysfs.c                  | 26 +++++++++++
>  5 files changed, 129 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/sysfs-entries.txt b/Documentation/sysfs-entries.txt
> index 6b483bba20..58d1f5a2df 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 e452d30630..4e93b1d7af 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 676794bef1..2a86842448 100644
> --- a/driver/main.c
> +++ b/driver/main.c
> @@ -19,11 +19,13 @@
>  #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>
>  #include <linux/vmalloc.h>
>  #include <linux/io.h>
> +#include <asm/barrier.h>
>  #include <asm/smp.h>
>  #include <asm/cacheflush.h>
>  #include <asm/tlbflush.h>
> @@ -77,6 +79,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* volatile console_page;
> +static bool console_available;
>  
>  #ifdef CONFIG_X86
>  bool jailhouse_use_vmcall;
> @@ -91,6 +95,23 @@ static void init_hypercall(void)
>  }
>  #endif
>  
> +static void copy_console_page(struct jailhouse_console *dst)
> +{
> +     unsigned int tail;
> +
> +     do {
> +             /* spin while hypervisor is writing to console */
> +             while (console_page->lock)
> +                     cpu_relax();
> +             tail = console_page->tail;
> +             rmb();
> +
> +             /* copy console page */
> +             memcpy(dst, console_page, sizeof(struct jailhouse_console));
> +             rmb();
> +     } while (console_page->tail != tail || console_page->lock);
> +}
> +
>  static long get_max_cpus(u32 cpu_set_size,
>                        const struct jailhouse_system __user *system_config)
>  {
> @@ -182,6 +203,77 @@ 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;

I would use a local var for "missed", check at the end if the passed
pointer is non-NULL, and only then write back.

> +
> +     /* check if tail overflowed */
> +     if (console->tail < head)
> +             delta = (0 - head) + console->tail;
> +     else
> +             delta = console->tail - head;

Maybe me mind is still frozen, but these two statements should generate
the same instructions, shouldn't they...?

> +
> +     /* 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)

Can you find some more telling names for this one vs.
"jailhouse_console_delta"? Both are missing some verb, and it's not
obvious in what they are different?

> +{
> +     int ret;
> +     struct jailhouse_console *console;
> +
> +     if (!jailhouse_enabled)
> +             return -EAGAIN;
> +
> +     if (!console_available)
> +             return -EPERM;
> +
> +     console = kmalloc(sizeof(struct jailhouse_console), GFP_KERNEL);
> +     if (console == NULL)
> +             return -ENOMEM;
> +
> +     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);
> +     return ret;
> +}
> +
>  /* See Documentation/bootstrap-interface.txt */
>  static int jailhouse_cmd_enable(struct jailhouse_system __user *arg)
>  {
> @@ -273,6 +365,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 +424,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 e01ca5b52f..fe322ead18 100644
> --- a/driver/main.h
> +++ b/driver/main.h
> @@ -22,5 +22,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 8da1f766ce..151a5bf46a 100644
> --- a/driver/sysfs.c
> +++ b/driver/sysfs.c
> @@ -309,6 +309,30 @@ 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;
> +
> +     if (mutex_lock_interruptible(&jailhouse_lock) != 0)
> +             return -EINTR;
> +
> +     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;

The "why" for terminating the buffer with 0 should be mentioned. It's
not clear to me at least

> +
> +     /* don't return error if jailhouse is not enabled */
> +     if (ret == -EAGAIN)
> +             ret = 0;
> +
> +     mutex_unlock(&jailhouse_lock);
> +
> +     return ret;
> +}
> +
>  static ssize_t enabled_show(struct device *dev, struct device_attribute 
> *attr,
>                           char *buffer)
>  {
> @@ -361,6 +385,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 +393,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,
> 

Jan

-- 
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.

Reply via email to