123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346 |
- // SPDX-License-Identifier: GPL-2.0-only
- /*
- * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
- */
- #define pr_fmt(fmt) "mem_buf_vm: " fmt
- #include <linux/of.h>
- #include <linux/xarray.h>
- #include <soc/qcom/secure_buffer.h>
- #include "mem-buf-dev.h"
- #include "mem-buf-ids.h"
- #define DEVNAME "mem_buf_vm"
- #define NUM_MEM_BUF_VM_MINORS 128
- static dev_t mem_buf_vm_devt;
- static struct class *mem_buf_vm_class;
- /*
- * VM objects have the same lifetime as this module.
- */
- static DEFINE_XARRAY_ALLOC(mem_buf_vm_minors);
- static DEFINE_XARRAY(mem_buf_vms);
- int current_vmid;
- #define PERIPHERAL_VM(_uname, _lname) \
- static struct mem_buf_vm vm_ ## _lname = { \
- .name = "qcom," #_lname, \
- .vmid = VMID_ ## _uname, \
- .allowed_api = 0, \
- }
- PERIPHERAL_VM(CP_TOUCH, cp_touch);
- PERIPHERAL_VM(CP_BITSTREAM, cp_bitstream);
- PERIPHERAL_VM(CP_PIXEL, cp_pixel);
- PERIPHERAL_VM(CP_NON_PIXEL, cp_non_pixel);
- PERIPHERAL_VM(CP_CAMERA, cp_camera);
- PERIPHERAL_VM(CP_SEC_DISPLAY, cp_sec_display);
- PERIPHERAL_VM(CP_SPSS_SP, cp_spss_sp);
- PERIPHERAL_VM(CP_CAMERA_PREVIEW, cp_camera_preview);
- PERIPHERAL_VM(CP_SPSS_SP_SHARED, cp_spss_sp_shared);
- PERIPHERAL_VM(CP_SPSS_HLOS_SHARED, cp_spss_hlos_shared);
- PERIPHERAL_VM(CP_CDSP, cp_cdsp);
- PERIPHERAL_VM(CP_APP, cp_app);
- static struct mem_buf_vm vm_trusted_vm = {
- .name = "qcom,trusted_vm",
- .vmid = VMID_TVM,
- .allowed_api = MEM_BUF_API_GUNYAH,
- };
- static struct mem_buf_vm vm_oemvm = {
- .name = "qcom,oemvm",
- .vmid = VMID_OEMVM,
- .allowed_api = MEM_BUF_API_GUNYAH,
- };
- static struct mem_buf_vm vm_hlos = {
- .name = "qcom,hlos",
- .vmid = VMID_HLOS,
- .allowed_api = 0,
- };
- struct mem_buf_vm *pdata_array[] = {
- &vm_trusted_vm,
- &vm_oemvm,
- &vm_hlos,
- &vm_cp_touch,
- &vm_cp_bitstream,
- &vm_cp_pixel,
- &vm_cp_non_pixel,
- &vm_cp_camera,
- &vm_cp_sec_display,
- &vm_cp_spss_sp,
- &vm_cp_camera_preview,
- &vm_cp_spss_sp_shared,
- &vm_cp_spss_hlos_shared,
- &vm_cp_cdsp,
- &vm_cp_app,
- NULL,
- };
- int mem_buf_current_vmid(void)
- {
- return current_vmid;
- }
- EXPORT_SYMBOL(mem_buf_current_vmid);
- /*
- * Opening this file acquires a refcount on vm->dev's kobject - see
- * chrdev_open(). So private data won't be free'd out from
- * under us.
- */
- static int mem_buf_vm_open(struct inode *inode, struct file *file)
- {
- struct mem_buf_vm *vm;
- vm = container_of(inode->i_cdev, struct mem_buf_vm, cdev);
- file->private_data = vm;
- return 0;
- }
- static const struct file_operations mem_buf_vm_fops = {
- .open = mem_buf_vm_open,
- };
- bool mem_buf_vm_uses_hyp_assign(void)
- {
- return current_vmid == VMID_HLOS;
- }
- EXPORT_SYMBOL(mem_buf_vm_uses_hyp_assign);
- /*
- * Use Gunyah API if any vm in the source or destination requires it.
- */
- int mem_buf_vm_uses_gunyah(int *vmids, unsigned int nr_acl_entries)
- {
- struct mem_buf_vm *vm;
- int i;
- for (i = 0; i < nr_acl_entries; i++) {
- vm = xa_load(&mem_buf_vms, vmids[i]);
- if (!vm) {
- pr_err_ratelimited("No vm with vmid=0x%x\n", vmids[i]);
- return -EINVAL;
- }
- if (vm->allowed_api & MEM_BUF_API_GUNYAH)
- return true;
- }
- vm = xa_load(&mem_buf_vms, current_vmid);
- if (!vm) {
- pr_err_ratelimited("No vm with vmid=0x%x\n", current_vmid);
- return PTR_ERR(vm);
- }
- if (vm->allowed_api & MEM_BUF_API_GUNYAH)
- return true;
- return false;
- }
- EXPORT_SYMBOL(mem_buf_vm_uses_gunyah);
- int mem_buf_fd_to_vmid(int fd)
- {
- int ret = -EINVAL;
- struct mem_buf_vm *vm;
- struct file *file;
- file = fget(fd);
- if (!file)
- return -EINVAL;
- if (file->f_op != &mem_buf_vm_fops) {
- pr_err_ratelimited("Invalid vm file type\n");
- fput(file);
- return -EINVAL;
- }
- vm = file->private_data;
- ret = vm->vmid;
- fput(file);
- return ret;
- }
- EXPORT_SYMBOL(mem_buf_fd_to_vmid);
- static void mem_buf_vm_device_release(struct device *dev)
- {
- struct mem_buf_vm *vm;
- vm = container_of(dev, struct mem_buf_vm, dev);
- kfree(vm);
- }
- /*
- * caller must fill in all fields of new_vm except for cdev & dev.
- */
- static int mem_buf_vm_add(struct mem_buf_vm *new_vm)
- {
- struct mem_buf_vm *vm;
- struct device *dev;
- int minor, ret;
- unsigned long idx;
- xa_for_each(&mem_buf_vm_minors, idx, vm) {
- if (!strcmp(vm->name, new_vm->name)) {
- pr_err("duplicate vm %s\n", vm->name);
- ret = -EINVAL;
- goto err_duplicate;
- }
- }
- ret = xa_alloc(&mem_buf_vm_minors, &minor, new_vm,
- XA_LIMIT(0, NUM_MEM_BUF_VM_MINORS - 1), GFP_KERNEL);
- if (ret < 0) {
- pr_err("no more minors\n");
- goto err_devt;
- }
- cdev_init(&new_vm->cdev, &mem_buf_vm_fops);
- dev = &new_vm->dev;
- device_initialize(dev);
- dev->devt = MKDEV(MAJOR(mem_buf_vm_devt), minor);
- dev->class = mem_buf_vm_class;
- dev->parent = NULL;
- dev->release = mem_buf_vm_device_release;
- dev_set_drvdata(dev, new_vm);
- dev_set_name(dev, "%s", new_vm->name);
- ret = xa_err(xa_store(&mem_buf_vms, new_vm->vmid, new_vm, GFP_KERNEL));
- if (ret)
- goto err_xa_store;
- ret = cdev_device_add(&new_vm->cdev, dev);
- if (ret) {
- pr_err("Adding cdev %s failed\n", new_vm->name);
- goto err_cdev_add;
- }
- return 0;
- err_cdev_add:
- xa_erase(&mem_buf_vms, new_vm->vmid);
- err_xa_store:
- xa_erase(&mem_buf_vm_minors, minor);
- put_device(dev);
- err_devt:
- err_duplicate:
- return ret;
- }
- static int mem_buf_vm_add_pdata(struct mem_buf_vm *pdata)
- {
- struct mem_buf_vm *vm;
- int ret;
- vm = kmemdup(pdata, sizeof(*vm), GFP_KERNEL);
- if (!vm)
- return -ENOMEM;
- ret = mem_buf_vm_add(vm);
- if (ret) {
- kfree(vm);
- return ret;
- }
- return 0;
- }
- static int mem_buf_vm_add_self(void)
- {
- struct mem_buf_vm *vm, *self;
- int ret;
- vm = xa_load(&mem_buf_vms, current_vmid);
- if (!vm)
- return PTR_ERR(vm);
- self = kzalloc(sizeof(*self), GFP_KERNEL);
- if (!self)
- return -ENOMEM;
- /* Create an aliased name */
- self->name = "qcom,self";
- self->vmid = vm->vmid;
- self->allowed_api = vm->allowed_api;
- ret = mem_buf_vm_add(self);
- if (ret) {
- kfree(self);
- return ret;
- }
- return 0;
- }
- static char *mem_buf_vm_devnode(struct device *dev, umode_t *mode)
- {
- return kasprintf(GFP_KERNEL, "mem_buf_vm/%s", dev_name(dev));
- }
- static int mem_buf_vm_put_class_device_cb(struct device *dev, void *data)
- {
- struct mem_buf_vm *vm = container_of(dev, struct mem_buf_vm, dev);
- cdev_device_del(&vm->cdev, dev);
- return 0;
- }
- int mem_buf_vm_init(struct device *dev)
- {
- struct mem_buf_vm **p;
- int ret, vmid;
- ret = of_property_read_u32(dev->of_node, "qcom,vmid", &vmid);
- if (ret) {
- dev_err(dev, "missing qcom,vmid property\n");
- return ret;
- }
- current_vmid = vmid;
- ret = alloc_chrdev_region(&mem_buf_vm_devt, 0, NUM_MEM_BUF_VM_MINORS,
- DEVNAME);
- if (ret)
- return ret;
- mem_buf_vm_class = class_create(THIS_MODULE, DEVNAME);
- if (IS_ERR(mem_buf_vm_class)) {
- ret = PTR_ERR(mem_buf_vm_class);
- goto err_class_create;
- }
- mem_buf_vm_class->devnode = mem_buf_vm_devnode;
- for (p = pdata_array; *p; p++) {
- ret = mem_buf_vm_add_pdata(*p);
- if (ret)
- goto err_pdata;
- }
- ret = mem_buf_vm_add_self();
- if (ret)
- goto err_self;
- return 0;
- err_self:
- err_pdata:
- xa_destroy(&mem_buf_vms);
- xa_destroy(&mem_buf_vm_minors);
- class_for_each_device(mem_buf_vm_class, NULL, NULL,
- mem_buf_vm_put_class_device_cb);
- class_destroy(mem_buf_vm_class);
- err_class_create:
- unregister_chrdev_region(mem_buf_vm_devt, NUM_MEM_BUF_VM_MINORS);
- return ret;
- }
- void mem_buf_vm_exit(void)
- {
- xa_destroy(&mem_buf_vms);
- xa_destroy(&mem_buf_vm_minors);
- class_for_each_device(mem_buf_vm_class, NULL, NULL,
- mem_buf_vm_put_class_device_cb);
- class_destroy(mem_buf_vm_class);
- unregister_chrdev_region(mem_buf_vm_devt, NUM_MEM_BUF_VM_MINORS);
- }
|