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(¨ist_len, ¨ist->length, sizeof(umlist_len))) + return -EFAULT; + + err = 0; + for (i = 0; i < umlist_len; i++) { + if (copy_from_user(&mapping, ¨ist->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(¨ist_len, ¨ist->length, sizeof(umlist_len))) + return -EFAULT; + + err = 0; + for (i = 0; i < umlist_len; i++) { + if (copy_from_user(&mapping, ¨ist->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(¨ist_len, ¨ist->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