static int tf_ctrl_device_release(struct inode *inode, struct file *file) { struct tf_connection *connection; dpr_info("%s(%u:%u, %p)\n", __func__, imajor(inode), iminor(inode), file); connection = tf_conn_from_file(file); tf_close(connection); dpr_info("%s(%p): Success\n", __func__, file); return 0; }
static int tf_device_release(struct inode *inode, struct file *file) { struct tf_connection *connection; dprintk(KERN_INFO "tf_device_release(%u:%u, %p)\n", imajor(inode), iminor(inode), file); connection = tf_conn_from_file(file); tf_close(connection); dprintk(KERN_INFO "tf_device_release(%p): Success\n", file); return 0; }
static long tf_device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { int result = S_SUCCESS; struct tf_connection *connection; union tf_command command; struct tf_command_header header; union tf_answer answer; u32 command_size; u32 answer_size; void *user_answer; dprintk(KERN_INFO "tf_device_ioctl(%p, %u, %p)\n", file, ioctl_num, (void *) ioctl_param); switch (ioctl_num) { case IOCTL_TF_GET_VERSION: /* ioctl is asking for the driver interface version */ result = TF_DRIVER_INTERFACE_VERSION; goto exit; case IOCTL_TF_EXCHANGE: /* * ioctl is asking to perform a message exchange with the Secure * Module */ /* * Make a local copy of the data from the user application * This routine checks the data is readable * * Get the header first. */ if (copy_from_user(&header, (struct tf_command_header *)ioctl_param, sizeof(struct tf_command_header))) { dprintk(KERN_ERR "tf_device_ioctl(%p): " "Cannot access ioctl parameter %p\n", file, (void *) ioctl_param); result = -EFAULT; goto exit; } /* size in words of u32 */ command_size = header.message_size + sizeof(struct tf_command_header)/sizeof(u32); if (command_size > sizeof(command)/sizeof(u32)) { dprintk(KERN_ERR "tf_device_ioctl(%p): " "Buffer overflow: too many bytes to copy %d\n", file, command_size); result = -EFAULT; goto exit; } if (copy_from_user(&command, (union tf_command *)ioctl_param, command_size * sizeof(u32))) { dprintk(KERN_ERR "tf_device_ioctl(%p): " "Cannot access ioctl parameter %p\n", file, (void *) ioctl_param); result = -EFAULT; goto exit; } connection = tf_conn_from_file(file); BUG_ON(connection == NULL); /* * The answer memory space address is in the operation_id field */ user_answer = (void *) command.header.operation_id; atomic_inc(&(connection->pending_op_count)); dprintk(KERN_WARNING "tf_device_ioctl(%p): " "Sending message type 0x%08x\n", file, command.header.message_type); switch (command.header.message_type) { case TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION: result = tf_open_client_session(connection, &command, &answer); break; case TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION: result = tf_close_client_session(connection, &command, &answer); break; case TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY: result = tf_register_shared_memory(connection, &command, &answer); break; case TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY: result = tf_release_shared_memory(connection, &command, &answer); break; case TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND: result = tf_invoke_client_command(connection, &command, &answer); break; case TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND: result = tf_cancel_client_command(connection, &command, &answer); break; default: dprintk(KERN_ERR "tf_device_ioctl(%p): " "Incorrect message type (0x%08x)!\n", connection, command.header.message_type); result = -EOPNOTSUPP; break; } atomic_dec(&(connection->pending_op_count)); if (result != 0) { dprintk(KERN_WARNING "tf_device_ioctl(%p): " "Operation returning error code 0x%08x)!\n", file, result); goto exit; } /* * Copy the answer back to the user space application. * The driver does not check this field, only copy back to user * space the data handed over by Secure World */ answer_size = answer.header.message_size + sizeof(struct tf_answer_header)/sizeof(u32); if (copy_to_user(user_answer, &answer, answer_size * sizeof(u32))) { dprintk(KERN_WARNING "tf_device_ioctl(%p): " "Failed to copy back the full command " "answer to %p\n", file, user_answer); result = -EFAULT; goto exit; } /* successful completion */ dprintk(KERN_INFO "tf_device_ioctl(%p): Success\n", file); break; case IOCTL_TF_GET_DESCRIPTION: { /* ioctl asking for the version information buffer */ struct tf_version_information_buffer *pInfoBuffer; dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION:(%p, %u, %p)\n", file, ioctl_num, (void *) ioctl_param); pInfoBuffer = ((struct tf_version_information_buffer *) ioctl_param); dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION1: " "driver_description=\"%64s\"\n", S_VERSION_STRING); if (copy_to_user(pInfoBuffer->driver_description, S_VERSION_STRING, strlen(S_VERSION_STRING) + 1)) { dprintk(KERN_ERR "tf_device_ioctl(%p): " "Fail to copy back the driver description " "to %p\n", file, pInfoBuffer->driver_description); result = -EFAULT; goto exit; } dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION2: " "secure_world_description=\"%64s\"\n", tf_get_description(&g_tf_dev.sm)); if (copy_to_user(pInfoBuffer->secure_world_description, tf_get_description(&g_tf_dev.sm), TF_DESCRIPTION_BUFFER_LENGTH)) { dprintk(KERN_WARNING "tf_device_ioctl(%p): " "Failed to copy back the secure world " "description to %p\n", file, pInfoBuffer->secure_world_description); result = -EFAULT; goto exit; } break; } default: dprintk(KERN_ERR "tf_device_ioctl(%p): " "Unknown IOCTL code 0x%08x!\n", file, ioctl_num); result = -EOPNOTSUPP; goto exit; } exit: return result; }
static long tf_ctrl_device_ioctl(struct file *file, unsigned int ioctl_num, unsigned long ioctl_param) { int result = S_SUCCESS; struct tf_pa_ctrl pa_ctrl; struct tf_device *dev = tf_get_device(); dpr_info("%s(%p, %u, %p)\n", __func__, file, ioctl_num, (void *) ioctl_param); mutex_lock(&dev->dev_mutex); if (ioctl_num != IOCTL_TF_PA_CTRL) { dpr_err("%s(%p): ioctl number is invalid (%p)\n", __func__, file, (void *)ioctl_num); result = -EFAULT; goto exit; } if ((ioctl_param & 0x3) != 0) { dpr_err("%s(%p): ioctl command message pointer is not word " "aligned (%p)\n", __func__, file, (void *)ioctl_param); result = -EFAULT; goto exit; } if (copy_from_user(&pa_ctrl, (struct tf_pa_ctrl *)ioctl_param, sizeof(struct tf_pa_ctrl))) { dpr_err("%s(%p): cannot access ioctl parameter (%p)\n", __func__, file, (void *)ioctl_param); result = -EFAULT; goto exit; } switch (pa_ctrl.nPACommand) { case TF_PA_CTRL_START: { struct tf_shmem_desc *shmem_desc = NULL; u32 shared_mem_descriptors[TF_MAX_COARSE_PAGES]; u32 descriptor_count; u32 offset; struct tf_connection *connection; dpr_info("%s(%p): Start the SMC PA (%d bytes) with conf " "(%d bytes)\n", __func__, file, pa_ctrl.pa_size, pa_ctrl.conf_size); connection = tf_conn_from_file(file); if (dev->workspace_addr == 0) { result = -ENOMEM; goto start_exit; } result = tf_validate_shmem_and_flags( (u32)pa_ctrl.conf_buffer, pa_ctrl.conf_size, TF_SHMEM_TYPE_READ); if (result != 0) goto start_exit; offset = 0; result = tf_map_shmem( connection, (u32)pa_ctrl.conf_buffer, TF_SHMEM_TYPE_READ, true, /* in user space */ shared_mem_descriptors, &offset, pa_ctrl.conf_size, &shmem_desc, &descriptor_count); if (result != 0) goto start_exit; if (descriptor_count > 1) { dpr_err("%s(%p): configuration file is too long (%d)\n", __func__, file, descriptor_count); result = -ENOMEM; goto start_exit; } result = tf_start(&dev->sm, dev->workspace_addr, dev->workspace_size, pa_ctrl.pa_buffer, pa_ctrl.pa_size, shared_mem_descriptors[0], offset, pa_ctrl.conf_size); if (result) dpr_err("SMC: start failed\n"); else dpr_info("SMC: started\n"); start_exit: tf_unmap_shmem(connection, shmem_desc, true); /* full cleanup */ break; } case TF_PA_CTRL_STOP: dpr_info("%s(%p): Stop the SMC PA\n", __func__, file); result = tf_power_management(&dev->sm, TF_POWER_OPERATION_SHUTDOWN); if (result) dpr_err("SMC: stop failed [0x%x]\n", result); else dpr_info("SMC: stopped\n"); break; default: result = -EOPNOTSUPP; break; } exit: mutex_unlock(&dev->dev_mutex); return result; }