[RFC v4][PATCH part-3 10/14] asidrv: Add ioctls to manage ASI mapped VA ranges

From: Alexandre Chartre
Date: Mon May 04 2020 - 11:08:10 EST


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

Signed-off-by: Alexandre Chartre <alexandre.chartre@xxxxxxxxxx>
---
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