static int tf_map_temp_shmem(struct tf_connection *connection, struct tf_command_param_temp_memref *temp_memref, u32 param_type, struct tf_shmem_desc **shmem_desc) { u32 flags; u32 error = S_SUCCESS; bool in_user_space = connection->owner != TF_CONNECTION_OWNER_KERNEL; dprintk(KERN_INFO "tf_map_temp_shmem(%p, " "0x%08x[size=0x%08x], offset=0x%08x)\n", connection, temp_memref->descriptor, temp_memref->size, temp_memref->offset); switch (param_type) { case TF_PARAM_TYPE_MEMREF_TEMP_INPUT: flags = TF_SHMEM_TYPE_READ; break; case TF_PARAM_TYPE_MEMREF_TEMP_OUTPUT: flags = TF_SHMEM_TYPE_WRITE; break; case TF_PARAM_TYPE_MEMREF_TEMP_INOUT: flags = TF_SHMEM_TYPE_WRITE | TF_SHMEM_TYPE_READ; break; default: error = -EINVAL; goto error; } if (temp_memref->descriptor == 0) { /* NULL tmpref */ temp_memref->offset = 0; *shmem_desc = NULL; } else if ((temp_memref->descriptor != 0) && (temp_memref->size == 0)) { /* Empty tmpref */ temp_memref->offset = temp_memref->descriptor; temp_memref->descriptor = 0; temp_memref->size = 0; *shmem_desc = NULL; } else { /* Map the temp shmem block */ u32 shared_mem_descriptors[TF_MAX_COARSE_PAGES]; u32 descriptor_count; if (in_user_space) { error = tf_validate_shmem_and_flags( temp_memref->descriptor, temp_memref->size, flags); if (error != 0) goto error; } error = tf_map_shmem( connection, temp_memref->descriptor, flags, in_user_space, shared_mem_descriptors, &(temp_memref->offset), temp_memref->size, shmem_desc, &descriptor_count); temp_memref->descriptor = shared_mem_descriptors[0]; } error: return error; }
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; }
/* * Registers a shared memory to the Secure World */ int tf_register_shared_memory( struct tf_connection *connection, union tf_command *command, union tf_answer *answer) { int error = 0; struct tf_shmem_desc *shmem_desc = NULL; bool in_user_space = connection->owner != TF_CONNECTION_OWNER_KERNEL; struct tf_command_register_shared_memory *msg = &command->register_shared_memory; dprintk(KERN_INFO "tf_register_shared_memory(%p) " "%p[0x%08X][0x%08x]\n", connection, (void *)msg->shared_mem_descriptors[0], msg->shared_mem_size, (u32)msg->memory_flags); if (in_user_space) { error = tf_validate_shmem_and_flags( msg->shared_mem_descriptors[0], msg->shared_mem_size, (u32)msg->memory_flags); if (error != 0) goto error; } /* Initialize message_size with no descriptors */ msg->message_size = (offsetof(struct tf_command_register_shared_memory, shared_mem_descriptors) - sizeof(struct tf_command_header)) / 4; /* Map the shmem block and update the message */ if (msg->shared_mem_size == 0) { /* Empty shared mem */ msg->shared_mem_start_offset = msg->shared_mem_descriptors[0]; } else { u32 descriptor_count; error = tf_map_shmem( connection, msg->shared_mem_descriptors[0], msg->memory_flags, in_user_space, msg->shared_mem_descriptors, &(msg->shared_mem_start_offset), msg->shared_mem_size, &shmem_desc, &descriptor_count); if (error != 0) { dprintk(KERN_ERR "tf_register_shared_memory: " "unable to map shared memory block\n"); goto error; } msg->message_size += descriptor_count; } /* * write the correct device context handle and the address of the shared * memory descriptor in the message */ msg->device_context = connection->device_context; msg->block_id = (u32)shmem_desc; /* Send the updated message */ error = tf_send_receive( &connection->dev->sm, command, answer, connection, true); if ((error != 0) || (answer->register_shared_memory.error_code != S_SUCCESS)) { dprintk(KERN_ERR "tf_register_shared_memory: " "operation failed. Unmap block\n"); goto error; } /* Saves the block handle returned by the secure world */ if (shmem_desc != NULL) shmem_desc->block_identifier = answer->register_shared_memory.block; /* successful completion */ dprintk(KERN_INFO "tf_register_shared_memory(%p):" " block_id=0x%08x block=0x%08x\n", connection, msg->block_id, answer->register_shared_memory.block); return 0; /* error completion */ error: tf_unmap_shmem( connection, shmem_desc, 0); if (error != 0) dprintk(KERN_ERR "tf_register_shared_memory returns %d\n", error); else dprintk(KERN_ERR "tf_register_shared_memory returns " "error_code 0x%08X\n", answer->register_shared_memory.error_code); return error; }