static int smcmod_send_buf_cmd(struct smcmod_buf_req *reqp) { int ret = 0; struct ion_client *ion_clientp = NULL; struct ion_handle *ion_cmd_handlep = NULL; struct ion_handle *ion_resp_handlep = NULL; void *cmd_vaddrp = NULL; void *resp_vaddrp = NULL; unsigned long cmd_buf_size = 0; unsigned long resp_buf_size = 0; /* sanity check the argument */ if (IS_ERR_OR_NULL(reqp)) return -EINVAL; /* sanity check the fds */ if (reqp->ion_cmd_fd < 0) return -EINVAL; /* create an ion client */ ion_clientp = msm_ion_client_create(UINT_MAX, "smcmod"); /* check for errors */ if (IS_ERR_OR_NULL(ion_clientp)) return -EINVAL; /* import the command buffer fd */ ion_cmd_handlep = ion_import_dma_buf(ion_clientp, reqp->ion_cmd_fd); /* sanity check the handle */ if (IS_ERR_OR_NULL(ion_cmd_handlep)) { ret = -EINVAL; goto buf_cleanup; } /* retrieve the size of the buffer */ if (ion_handle_get_size(ion_clientp, ion_cmd_handlep, &cmd_buf_size) < 0) { ret = -EINVAL; goto buf_cleanup; } /* ensure that the command buffer size is not * greater than the size of the buffer. */ if (reqp->cmd_len > cmd_buf_size) { ret = -EINVAL; goto buf_cleanup; } /* map the area to get a virtual address */ cmd_vaddrp = ion_map_kernel(ion_clientp, ion_cmd_handlep); /* sanity check the address */ if (IS_ERR_OR_NULL(cmd_vaddrp)) { ret = -EINVAL; goto buf_cleanup; } /* check if there is a response buffer */ if (reqp->ion_resp_fd >= 0) { /* import the handle */ ion_resp_handlep = ion_import_dma_buf(ion_clientp, reqp->ion_resp_fd); /* sanity check the handle */ if (IS_ERR_OR_NULL(ion_resp_handlep)) { ret = -EINVAL; goto buf_cleanup; } /* retrieve the size of the buffer */ if (ion_handle_get_size(ion_clientp, ion_resp_handlep, &resp_buf_size) < 0) { ret = -EINVAL; goto buf_cleanup; } /* ensure that the command buffer size is not * greater than the size of the buffer. */ if (reqp->resp_len > resp_buf_size) { ret = -EINVAL; goto buf_cleanup; } /* map the area to get a virtual address */ resp_vaddrp = ion_map_kernel(ion_clientp, ion_resp_handlep); /* sanity check the address */ if (IS_ERR_OR_NULL(resp_vaddrp)) { ret = -EINVAL; goto buf_cleanup; } } /* No need to flush the cache lines for the command buffer here, * because the buffer will be flushed by scm_call. */ /* call scm function to switch to secure world */ reqp->return_val = scm_call(reqp->service_id, reqp->command_id, cmd_vaddrp, reqp->cmd_len, resp_vaddrp, reqp->resp_len); /* The cache lines for the response buffer have already been * invalidated by scm_call before returning. */ buf_cleanup: /* if the client and handle(s) are valid, free them */ if (!IS_ERR_OR_NULL(ion_clientp)) { if (!IS_ERR_OR_NULL(ion_cmd_handlep)) { if (!IS_ERR_OR_NULL(cmd_vaddrp)) ion_unmap_kernel(ion_clientp, ion_cmd_handlep); ion_free(ion_clientp, ion_cmd_handlep); } if (!IS_ERR_OR_NULL(ion_resp_handlep)) { if (!IS_ERR_OR_NULL(resp_vaddrp)) ion_unmap_kernel(ion_clientp, ion_resp_handlep); ion_free(ion_clientp, ion_resp_handlep); } ion_client_destroy(ion_clientp); } return ret; }
static long ion_test_ioctl(struct file *file, unsigned cmd, unsigned long arg) { int ret; ion_phys_addr_t phys_addr; void *addr; size_t len; unsigned long flags, size; struct msm_ion_test *ion_test = file->private_data; struct ion_test_data *test_data = &ion_test->test_data; switch (cmd) { case IOC_ION_KCLIENT_CREATE: { ret = create_ion_client(ion_test); break; } case IOC_ION_KCLIENT_DESTROY: { free_ion_client(ion_test); ret = 0; break; } case IOC_ION_KALLOC: { if (copy_from_user(test_data, (void __user *)arg, sizeof(struct ion_test_data))) return -EFAULT; ret = alloc_ion_buf(ion_test, test_data); if (ret) pr_info("allocating ion buffer failed\n"); break; } case IOC_ION_KFREE: { free_ion_buf(ion_test); ret = 0; break; } case IOC_ION_KPHYS: { ret = ion_phys(ion_test->ion_client, ion_test->ion_handle, &phys_addr, &len); if (!ret) pr_info("size is 0x%x\n phys addr 0x%x", len, (unsigned int)phys_addr); break; } case IOC_ION_KMAP: { addr = ion_map_kernel(ion_test->ion_client, ion_test->ion_handle); if (IS_ERR_OR_NULL(addr)) { ret = -EIO; pr_info("mapping kernel buffer failed\n"); } else { ret = 0; test_data->vaddr = (unsigned long)addr; } break; } case IOC_ION_KUMAP: { ion_unmap_kernel(ion_test->ion_client, ion_test->ion_handle); ret = 0; break; } case IOC_ION_UIMPORT: { if (copy_from_user(test_data, (void __user *)arg, sizeof(struct ion_test_data))) return -EFAULT; ion_test->ion_handle = ion_import_dma_buf(ion_test->ion_client, test_data->shared_fd); if (IS_ERR_OR_NULL(ion_test->ion_handle)) { ret = -EIO; pr_info("import of user buf failed\n"); } else ret = 0; break; } case IOC_ION_UBUF_FLAGS: { ret = ion_handle_get_flags(ion_test->ion_client, ion_test->ion_handle, &flags); if (ret) pr_info("user flags cannot be retrieved\n"); else if (copy_to_user((void __user *)arg, &flags, sizeof(unsigned long))) ret = -EFAULT; break; } case IOC_ION_UBUF_SIZE: { ret = ion_handle_get_size(ion_test->ion_client, ion_test->ion_handle, &size); if (ret) pr_info("buffer size cannot be retrieved\n"); else if (copy_to_user((void __user *)arg, &size, sizeof(unsigned long))) ret = -EFAULT; break; } case IOC_ION_WRITE_VERIFY: { write_pattern(test_data->vaddr, test_data->size); if (verify_pattern(test_data->vaddr, test_data->size)) { pr_info("verify of mapped buf failed\n"); ret = -EIO; } else ret = 0; break; } case IOC_ION_VERIFY: { if (verify_pattern(test_data->vaddr, test_data->size)) { pr_info("fail in verifying imported buffer\n"); ret = -EIO; } else ret = 0; break; } case IOC_ION_SEC: { ret = msm_ion_secure_heap(ION_CP_MM_HEAP_ID); if (ret) pr_info("unable to secure heap\n"); else pr_info("able to secure heap\n"); break; } case IOC_ION_UNSEC: { ret = msm_ion_unsecure_heap(ION_CP_MM_HEAP_ID); if (ret) pr_info("unable to unsecure heap\n"); else pr_info("able to unsecure heap\n"); break; } default: { pr_info("command not supproted\n"); ret = -EINVAL; } }; return ret; }