Add ioctls to list, add, clear ASI mapped VA ranges.

Signed-off-by: Alexandre Chartre <alexandre.char...@oracle.com>
---
 drivers/staging/asi/asidrv.c | 138 +++++++++++++++++++++++++++++++++++
 drivers/staging/asi/asidrv.h |  26 +++++++
 2 files changed, 164 insertions(+)

diff --git a/drivers/staging/asi/asidrv.c b/drivers/staging/asi/asidrv.c
index e6edfbe5acea..9d9784629833 100644
--- a/drivers/staging/asi/asidrv.c
+++ b/drivers/staging/asi/asidrv.c
@@ -866,10 +866,137 @@ static int asidrv_ioctl_log_fault_stack(struct asi *asi, 
bool log_stack)
        return 0;
 }
 
+/*
+ * ASI decorated pagetable ioctls
+ */
+
+static int asidrv_ioctl_add_mapping(struct dpt *dpt, unsigned long arg)
+{
+       struct asidrv_mapping_list __user *umlist;
+       struct asidrv_mapping mapping;
+       __u32 umlist_len;
+       int i, err;
+
+       umlist = (struct asidrv_mapping_list *)arg;
+       if (copy_from_user(&umlist_len, &umlist->length, sizeof(umlist_len)))
+               return -EFAULT;
+
+       err = 0;
+       for (i = 0; i < umlist_len; i++) {
+               if (copy_from_user(&mapping, &umlist->mapping[i],
+                                  sizeof(mapping))) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               pr_debug("add mapping %llx/%llx/%u %s\n",
+                        mapping.addr, mapping.size, mapping.level,
+                        mapping.percpu ? "percpu" : "");
+
+               if (mapping.percpu) {
+                       if (mapping.level != PGT_LEVEL_PTE) {
+                               err = -EINVAL;
+                               break;
+                       }
+                       err = dpt_map_percpu(dpt, (void *)mapping.addr,
+                                            mapping.size);
+               } else {
+                       err = dpt_map_range(dpt, (void *)mapping.addr,
+                                           mapping.size, mapping.level);
+               }
+               if (err)
+                       break;
+       }
+
+       if (err)
+               return (i == 0) ? err : i;
+
+       return 0;
+}
+
+static int asidrv_ioctl_clear_mapping(struct dpt *dpt, unsigned long arg)
+{
+       struct asidrv_mapping_list __user *umlist;
+       struct asidrv_mapping mapping;
+       __u32 umlist_len;
+       int err, i;
+
+       umlist = (struct asidrv_mapping_list *)arg;
+       if (copy_from_user(&umlist_len, &umlist->length, sizeof(umlist_len)))
+               return -EFAULT;
+
+       err = 0;
+       for (i = 0; i < umlist_len; i++) {
+               if (copy_from_user(&mapping, &umlist->mapping[i],
+                                  sizeof(mapping))) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               pr_debug("clear mapping %llx %s\n",
+                        mapping.addr, mapping.percpu ? "percpu" : "");
+
+               if (mapping.percpu)
+                       dpt_unmap_percpu(dpt, (void *)mapping.addr);
+               else
+                       dpt_unmap(dpt, (void *)mapping.addr);
+       }
+
+       if (err)
+               return (i == 0) ? err : i;
+
+       return 0;
+}
+
+static int asidrv_ioctl_list_mapping(struct dpt *dpt, unsigned long arg)
+{
+       struct asidrv_mapping_list __user *umlist;
+       struct asidrv_mapping_list *mlist;
+       struct dpt_range_mapping *range;
+       unsigned long addr;
+       size_t mlist_size;
+       __u32 umlist_len;
+       int i;
+
+       umlist = (struct asidrv_mapping_list *)arg;
+       if (copy_from_user(&umlist_len, &umlist->length, sizeof(umlist_len)))
+               return -EFAULT;
+
+       umlist_len = min_t(unsigned int, umlist_len, 512);
+
+       mlist_size = sizeof(*mlist) +
+               sizeof(struct asidrv_mapping) * umlist_len;
+       mlist = kzalloc(mlist_size, GFP_KERNEL);
+       if (!mlist)
+               return -ENOMEM;
+
+       i = 0;
+       list_for_each_entry(range, &dpt->mapping_list, list) {
+               if (i < umlist_len) {
+                       addr = (__u64)range->ptr;
+                       mlist->mapping[i].addr = addr;
+                       mlist->mapping[i].size = range->size;
+                       mlist->mapping[i].level = range->level;
+               }
+               i++;
+       }
+       mlist->length = i;
+
+       if (copy_to_user(umlist, mlist, mlist_size)) {
+               kfree(mlist);
+               return -EFAULT;
+       }
+
+       kfree(mlist);
+
+       return 0;
+}
+
 static long asidrv_ioctl(struct file *filp, unsigned int cmd, unsigned long 
arg)
 {
        struct asidrv_test *test = asidrv_test;
        struct asi *asi = test->asi;
+       struct dpt *dpt = test->dpt;
 
        switch (cmd) {
 
@@ -884,6 +1011,17 @@ static long asidrv_ioctl(struct file *filp, unsigned int 
cmd, unsigned long arg)
        case ASIDRV_IOCTL_LOG_FAULT_STACK:
                return asidrv_ioctl_log_fault_stack(asi, arg);
 
+       /* ASI decorated pagetable ioctls */
+
+       case ASIDRV_IOCTL_LIST_MAPPING:
+               return asidrv_ioctl_list_mapping(dpt, arg);
+
+       case ASIDRV_IOCTL_ADD_MAPPING:
+               return asidrv_ioctl_add_mapping(dpt, arg);
+
+       case ASIDRV_IOCTL_CLEAR_MAPPING:
+               return asidrv_ioctl_clear_mapping(dpt, arg);
+
        /* Test ioctls */
 
        case ASIDRV_IOCTL_RUN_SEQUENCE:
diff --git a/drivers/staging/asi/asidrv.h b/drivers/staging/asi/asidrv.h
index 99ab9843e36b..f042106419db 100644
--- a/drivers/staging/asi/asidrv.h
+++ b/drivers/staging/asi/asidrv.h
@@ -48,6 +48,20 @@ enum asidrv_run_error {
 #define ASIDRV_IOCTL_CLEAR_FAULT       _IO('a', 3)
 #define ASIDRV_IOCTL_LOG_FAULT_STACK   _IO('a', 4)
 
+/*
+ * ASIDRV_IOCTL_ADD_MAPPING: add mapping to the ASI.
+ *
+ * User should set 'length' with the number of mapping described in the
+ * 'mapping' array.
+ * Return value:
+ *   -1   - error no mapping was added
+ *    0   - no error, all mappings were added
+ *   N>0  - error but the first N mappings were added
+ */
+#define ASIDRV_IOCTL_ADD_MAPPING       _IOWR('a', 5, struct 
asidrv_mapping_list)
+#define ASIDRV_IOCTL_CLEAR_MAPPING     _IOW('a', 6, struct asidrv_mapping_list)
+#define ASIDRV_IOCTL_LIST_MAPPING      _IOWR('a', 7, struct 
asidrv_mapping_list)
+
 #define ASIDRV_KSYM_NAME_LEN   128
 /*
  * We need KSYM_SYMBOL_LEN to lookup symbol. However it's not part of
@@ -73,4 +87,16 @@ struct asidrv_fault_list {
        struct asidrv_fault fault[0];
 };
 
+struct asidrv_mapping {
+       __u64 addr;
+       __u64 size;
+       __u32 level;
+       __u32 percpu;
+};
+
+struct asidrv_mapping_list {
+       __u32 length;
+       struct asidrv_mapping mapping[0];
+};
+
 #endif
-- 
2.18.2

Reply via email to