On 27/01/20 7:26 pm, [email protected] wrote:
From: Nikhil Devshatwar <[email protected]>

Implement regmap as a unit, Use reg_map_data as book keeping
data structure per cell.

Register a MMIO handler for each regmap region and handle the
mmio access based on the regmap described in the config.

Implement the regmap_modify_root to map and unmap the regmap
access from the root cell while creating inmate cells.

Signed-off-by: Nikhil Devshatwar <[email protected]>
---
  hypervisor/Makefile                   |   2 +-
  hypervisor/include/jailhouse/cell.h   |   2 +
  hypervisor/include/jailhouse/regmap.h |  47 +++++
  hypervisor/regmap.c                   | 258 ++++++++++++++++++++++++++
  4 files changed, 308 insertions(+), 1 deletion(-)
  create mode 100644 hypervisor/include/jailhouse/regmap.h
  create mode 100644 hypervisor/regmap.c

diff --git a/hypervisor/Makefile b/hypervisor/Makefile
index 893ead42..62c86a4b 100644
--- a/hypervisor/Makefile
+++ b/hypervisor/Makefile
@@ -36,7 +36,7 @@ ifneq ($(wildcard $(INC_CONFIG_H)),)
  KBUILD_CFLAGS += -include $(INC_CONFIG_H)
  endif
-CORE_OBJECTS = setup.o printk.o paging.o control.o lib.o mmio.o pci.o ivshmem.o
+CORE_OBJECTS = setup.o printk.o paging.o control.o lib.o mmio.o pci.o 
ivshmem.o regmap.o
  CORE_OBJECTS += uart.o uart-8250.o
ifdef CONFIG_JAILHOUSE_GCOV
diff --git a/hypervisor/include/jailhouse/cell.h 
b/hypervisor/include/jailhouse/cell.h
index c804a5df..90575bb9 100644
--- a/hypervisor/include/jailhouse/cell.h
+++ b/hypervisor/include/jailhouse/cell.h
@@ -69,6 +69,8 @@ struct cell {
        unsigned int num_mmio_regions;
        /** Maximum number of MMIO regions. */
        unsigned int max_mmio_regions;
+       /** List of register maps assigned to this cell. */
+       struct reg_map_data *regmap;
  };
extern struct cell root_cell;
diff --git a/hypervisor/include/jailhouse/regmap.h 
b/hypervisor/include/jailhouse/regmap.h
new file mode 100644
index 00000000..98faf2c8
--- /dev/null
+++ b/hypervisor/include/jailhouse/regmap.h
@@ -0,0 +1,47 @@
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors:
+ *  Nikhil Devshatwar <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#ifndef _JAILHOUSE_REGMAP_H
+#define _JAILHOUSE_REGMAP_H
+
+#include <jailhouse/types.h>
+#include <asm/mmio.h>
+#include <jailhouse/cell-config.h>
+
+struct cell;
+
+/**
+ * @defgroup REGMAP Regmap subsystem
+ *
+ * This subsystem provides interpretation and handling of intercepted
+ * register accesses performed by cells.
+ *
+ * @{
+ */
+
+#define JAILHOUSE_REGMAP_WORDS         8
+#define JAILHOUSE_REGMAP_BITS          (JAILHOUSE_REGMAP_WORDS * 32)
+
+/** Register map description */
+struct reg_map_data {
+       /** Reference to regmap defined in config */
+       const struct jailhouse_regmap *info;
+       /** Owning cell */
+       struct cell *cell;
+       /** virt address where this regmap is mapped */
+       void *map_base;
+       /** Ownership details for each register */
+       u32 reg_bitmap[JAILHOUSE_REGMAP_WORDS];
+};
+
+/** @} REGMAP */
+#endif /* !_JAILHOUSE_REGMAP_H */
diff --git a/hypervisor/regmap.c b/hypervisor/regmap.c
new file mode 100644
index 00000000..9f3d32dc
--- /dev/null
+++ b/hypervisor/regmap.c
@@ -0,0 +1,258 @@
+/*
+ * Jailhouse, a Linux-based partitioning hypervisor
+ *
+ * Copyright (c) 2019 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors:
+ *  Nikhil Devshatwar <[email protected]>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2.  See
+ * the COPYING file in the top-level directory.
+ */
+
+#include <jailhouse/cell.h>
+#include <jailhouse/control.h>
+#include <jailhouse/paging.h>
+#include <jailhouse/printk.h>
+#include <jailhouse/unit.h>
+#include <jailhouse/percpu.h>
+#include <jailhouse/regmap.h>
+
+static inline bool regmap_is_enabled(struct reg_map_data *regmap, int reg)
+{
+       u32 idx, mask;
+
+       idx = reg / 32;
+       mask = 1 << (reg % 32);
+
+       return regmap->reg_bitmap[idx] & mask ? 1 : 0;
+}
+
+static inline void regmap_enable(struct reg_map_data *regmap, int reg)
+{
+       u32 idx, mask;
+
+       idx = reg / 32;
+       mask = 1 << (reg % 32);
+
+       regmap->reg_bitmap[idx] |= mask;
+}
+
+static inline void regmap_disable(struct reg_map_data *regmap, int reg)
+{
+       u32 idx, mask;
+
+       idx = reg / 32;
+       mask = 1 << (reg % 32);
+
+       regmap->reg_bitmap[idx] &= ~mask;
+}
+
+/**
+ * Find the regmap which degines the ownership bitmap for
+ * the register address provided.
+ *
+ * @param cell         Cell in which to search.
+ * @param addr         Register address to match
+ * @param idx          Pointer to index, populated with index of register in
+ *                     the matching regmap
+ *
+ * @return Valid reg_map_data or NULL when not found.
+ */
+static struct reg_map_data *cell_get_regmap(struct cell *cell,
+       unsigned long addr, unsigned int *idx)
+{
+       const struct jailhouse_regmap *info;
+       struct reg_map_data *regmap;
+       unsigned long start, end;
+       u32 i;
+
+       for (i = 0; i < cell->config->num_regmaps; i++) {
+               regmap = &cell->regmap[i];
+               info = regmap->info;
+               start = (unsigned long)info->reg_base;
+               end = (unsigned long)start + info->reg_size * info->reg_count;
+
+               if (addr < start || addr >= end)
+                       continue;
+
+               *idx = (addr - info->reg_base) / info->reg_size;
+               return regmap;
+       }
+       return NULL;
+}
+
+/**
+ * Handle emulation of regmap access as per permission bitmap
+ * Check regmap access permissions and ownership
+ * Based on that, allow or forbid the MMIOs access to register
+ *
+ * @param arg          Private argument, reg_map_data.
+ * @param mmio         describes the mmio access which caused the fault
+ *
+ * @return             MMIO_HANDLED if the access is as per regmap description,
+ *                     MMIO_ERROR if it violates some of the permissions,
+ */
+static enum mmio_result regmap_handler(void *arg, struct mmio_access *mmio)
+{
+       struct reg_map_data *regmap = (struct reg_map_data *)arg;
+       const struct jailhouse_regmap *info;
+       unsigned int idx;
+
+       info = regmap->info;
+       idx = mmio->address / info->reg_size;
+
+       if (mmio->is_write) {
+               if ((info->flags & JAILHOUSE_MEM_WRITE) == 0)
+                       return MMIO_ERROR;
+       } else {
+               if ((info->flags & JAILHOUSE_MEM_READ) == 0)
+                       return MMIO_ERROR;
+       }
+
+       if (regmap_is_enabled(regmap, idx)) {
+               mmio_perform_access(regmap->map_base, mmio);
+               return MMIO_HANDLED;
+       }  else {
+               printk("MMIO access disabled\n");
+               return MMIO_ERROR;
+       }
+}
+
+/**
+ * Modify root_cell's bitmap to (un)mask the registers defined in inmate cell.
+ * Ignore if the root cell does not describe the regmap used by inmate
+ * Handles the case where root cell describes the registers using
+ * different address range
+ *
+ * @param cell         inmate cell handle.
+ * @param regmap       register (un)map to be removed from root_cell.
+ * @param map          true to map the regmap, false to unmap.
+ *
+ * @return 0 on successfully (un)mapping the regmap.
+ */
+static int regmap_modify_root(struct cell *cell, struct reg_map_data *regmap,
+               bool map)
+{
+       const struct jailhouse_regmap *info = regmap->info;
+       struct reg_map_data *root_regmap = NULL;
+       unsigned long long addr;
+       u32 reg, idx;
+
+       if (cell == &root_cell)
+               return 0;
+       if (info->flags & JAILHOUSE_MEM_ROOTSHARED)
+               return 0;
+
+       for (reg = 0; reg < info->reg_count; reg++) {
+
+               addr = info->reg_base + reg * info->reg_size;
+               if (!root_regmap) {
+                       root_regmap = cell_get_regmap(&root_cell, addr, &idx);
+                       if (!root_regmap)
+                               continue;
+               }
+
+               if (regmap_is_enabled(regmap, reg)) {
+                       if (map) {
+                               regmap_enable(root_regmap, idx);
+
+                       /* For unmapping, ensure that its mapped in root cell 
regmap */
+                       } else if (regmap_is_enabled(root_regmap, idx)) {
+
+                               regmap_disable(root_regmap, idx);
+                       } else {
+                               printk("ERROR: Root cell does not own bitmap for reg 
%llx\n",
+                                               addr);
+                               return -EINVAL;
+                       }
+               }
+
+               /* reuse the same root_regmap for next register if idx is 
within limit */
+               idx++;
+               if (idx >= root_regmap->info->reg_count)
+                       root_regmap = NULL;
+       }
+       return 0;
+}
+
+static int regmap_cell_init(struct cell *cell)
+{
+       const struct jailhouse_regmap *info;
+       struct reg_map_data *regmap;
+       u32 i, num_pages, size;
+       int ret;
+
+       if (cell->config->num_regmaps == 0)
+               return 0;
+
+       num_pages = PAGES(cell->config->num_regmaps * sizeof(struct 
reg_map_data));
+       cell->regmap = page_alloc(&mem_pool, num_pages);
+       if (!cell->regmap)
+               return -ENOMEM;
+
+       info = jailhouse_cell_regmaps(cell->config);
+       for (i = 0; i < cell->config->num_regmaps; i++, info++) {
+
+               regmap = &cell->regmap[i];
+               regmap->info = info;
+               regmap->cell = cell;
+               size = info->reg_size * info->reg_count;
+
+               if (info->reg_count > JAILHOUSE_REGMAP_BITS ||
+                   (info->flags & (JAILHOUSE_MEM_READ | JAILHOUSE_MEM_WRITE)) 
== 0)
+                       goto invalid;
+
+               regmap->map_base = paging_map_device(info->reg_base, size);
+               if (!regmap->map_base)
+                       return -ENOMEM;
+
+               memcpy(regmap->reg_bitmap, info->reg_bitmap,
+                       sizeof(regmap->reg_bitmap));
+
+               mmio_region_register(cell, info->reg_base, size,
+                       regmap_handler, regmap);
+
+               /* Unmap the memory so that handler can be triggered */
+               ret = paging_destroy(&cell->arch.mm, info->reg_base, size,
+                               PAGING_COHERENT);

Jan/Chase,

I was doing some more testing / debug with this.
I root caused that the paging_destroy call does not take effect.

I have the fix (7cffb9b7d54d "core: fix hugepage splitting in paging_destroy") from the next branch
Do we have one more bug causing the paging_destroy to be ignored?

Regards,
Nikhil D
+               if (ret)
+                       goto invalid;
+
+               ret = regmap_modify_root(cell, regmap, false);
+               if (ret)
+                       goto invalid;
+       }
+
+       return 0;
+invalid:
+       page_free(&mem_pool, cell->regmap, 1);
+       return -EINVAL;
+}
+
+static void regmap_cell_exit(struct cell *cell)
+{
+       struct reg_map_data *regmap;
+       u32 i, num_pages;
+
+       for (i = 0; i < cell->config->num_regmaps; i++) {
+               regmap = &cell->regmap[i];
+               regmap_modify_root(cell, regmap, true);
+       }
+
+       num_pages = PAGES(cell->config->num_regmaps);
+       page_free(&mem_pool, cell->regmap, num_pages);
+}
+
+static int regmap_init(void)
+{
+       return regmap_cell_init(&root_cell);
+}
+
+static unsigned int regmap_mmio_count_regions(struct cell *cell)
+{
+       return cell->config->num_regmaps;
+}
+
+DEFINE_UNIT_SHUTDOWN_STUB(regmap);
+DEFINE_UNIT(regmap, "regmap");

--
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].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jailhouse-dev/8676e5d1-c804-f101-ebe4-0530ee47148c%40ti.com.

Reply via email to