/* * Closes a client session from the Secure World */ int tf_close_client_session( struct tf_connection *connection, union tf_command *command, union tf_answer *answer) { int error = 0; dprintk(KERN_DEBUG "tf_close_client_session(%p)\n", connection); command->close_client_session.message_size = (sizeof(struct tf_command_close_client_session) - sizeof(struct tf_command_header)) / 4; command->close_client_session.device_context = connection->device_context; error = tf_send_receive( &connection->dev->sm, command, answer, connection, true); if (error != 0) dprintk(KERN_ERR "tf_close_client_session returns %d\n", error); else dprintk(KERN_ERR "tf_close_client_session returns " "error 0x%08X\n", answer->close_client_session.error_code); return error; }
/* * Releases a shared memory from the Secure World */ int tf_release_shared_memory( struct tf_connection *connection, union tf_command *command, union tf_answer *answer) { int error = 0; dprintk(KERN_DEBUG "tf_release_shared_memory(%p)\n", connection); command->release_shared_memory.message_size = (sizeof(struct tf_command_release_shared_memory) - sizeof(struct tf_command_header)) / 4; command->release_shared_memory.device_context = connection->device_context; error = tf_send_receive( &connection->dev->sm, command, answer, connection, true); if ((error != 0) || (answer->release_shared_memory.error_code != S_SUCCESS)) goto error; /* Use block_id to get back the pointer to shmem_desc */ tf_unmap_shmem( connection, (struct tf_shmem_desc *) answer->release_shared_memory.block_id, 0); /* successful completion */ dprintk(KERN_INFO "tf_release_shared_memory(%p):" " block_id=0x%08x block=0x%08x\n", connection, answer->release_shared_memory.block_id, command->release_shared_memory.block); return 0; error: if (error != 0) dprintk(KERN_ERR "tf_release_shared_memory returns %d\n", error); else dprintk(KERN_ERR "tf_release_shared_memory returns " "nChannelStatus 0x%08X\n", answer->release_shared_memory.error_code); return error; }
/* * Perform a Secure World shutdown operation. * The routine does not return if the operation succeeds. * the routine returns an appropriate error code if * the operation fails. */ int tf_pm_shutdown(struct tf_comm *comm) { int error; union tf_command command; union tf_answer answer; dprintk(KERN_INFO "tf_pm_shutdown()\n"); memset(&command, 0, sizeof(command)); command.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT; command.header.message_size = (sizeof(struct tf_command_management) - sizeof(struct tf_command_header))/sizeof(u32); command.management.command = TF_MANAGEMENT_SHUTDOWN; error = tf_send_receive( comm, &command, &answer, NULL, false); if (error != 0) { dprintk(KERN_ERR "tf_pm_shutdown(): " "tf_send_receive failed (error %d)!\n", error); return error; } #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT if (answer.header.error_code != 0) dprintk(KERN_ERR "tf_driver: shutdown failed.\n"); else dprintk(KERN_INFO "tf_driver: shutdown succeeded.\n"); #endif return answer.header.error_code; }
/* * Cancels a client command from the Secure World */ int tf_cancel_client_command( struct tf_connection *connection, union tf_command *command, union tf_answer *answer) { int error = 0; dprintk(KERN_DEBUG "tf_cancel_client_command(%p)\n", connection); command->cancel_client_operation.device_context = connection->device_context; command->cancel_client_operation.message_size = (sizeof(struct tf_command_cancel_client_operation) - sizeof(struct tf_command_header)) / 4; error = tf_send_receive( &connection->dev->sm, command, answer, connection, true); if ((error != 0) || (answer->cancel_client_operation.error_code != S_SUCCESS)) goto error; /* successful completion */ return 0; error: if (error != 0) dprintk(KERN_ERR "tf_cancel_client_command returns %d\n", error); else dprintk(KERN_ERR "tf_cancel_client_command returns " "nChannelStatus 0x%08X\n", answer->cancel_client_operation.error_code); return error; }
int tf_delayed_secure_resume(void) { int ret; union tf_command message; union tf_answer answer; struct tf_device *dev = tf_get_device(); spin_lock(&tf_delayed_resume_lock); if (likely(tf_need_delayed_resume == DELAYED_RESUME_NONE)) { spin_unlock(&tf_delayed_resume_lock); return 0; } if (unlikely(tf_need_delayed_resume == DELAYED_RESUME_ONGOING)) { spin_unlock(&tf_delayed_resume_lock); /* * Wait for the other caller to actually finish the delayed * resume operation */ while (tf_need_delayed_resume != DELAYED_RESUME_NONE) cpu_relax(); return 0; } tf_need_delayed_resume = DELAYED_RESUME_ONGOING; spin_unlock(&tf_delayed_resume_lock); /* * When the system leaves CORE OFF, HWA are configured as secure. We * need them as public for the Linux Crypto API. */ memset(&message, 0, sizeof(message)); message.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT; message.header.message_size = (sizeof(struct tf_command_management) - sizeof(struct tf_command_header))/sizeof(u32); message.management.command = TF_MANAGEMENT_RESUME_FROM_CORE_OFF; ret = tf_send_receive(&dev->sm, &message, &answer, NULL, false); if (ret) { printk(KERN_ERR "tf_pm_resume(%p): " "tf_send_receive failed (error %d)!\n", &dev->sm, ret); unregister_smc_public_crypto_digest(); unregister_smc_public_crypto_aes(); return ret; } if (answer.header.error_code) { unregister_smc_public_crypto_digest(); unregister_smc_public_crypto_aes(); } spin_lock(&tf_delayed_resume_lock); tf_need_delayed_resume = DELAYED_RESUME_NONE; spin_unlock(&tf_delayed_resume_lock); return answer.header.error_code; }
/* * Opens a client session to the Secure World */ int tf_open_client_session( struct tf_connection *connection, union tf_command *command, union tf_answer *answer) { int error = 0; struct tf_shmem_desc *shmem_desc[4] = {NULL}; u32 i; dprintk(KERN_INFO "tf_open_client_session(%p)\n", connection); /* * Initialize the message size with no login data. This will be later * adjusted the the cases below */ command->open_client_session.message_size = (sizeof(struct tf_command_open_client_session) - 20 - sizeof(struct tf_command_header))/4; switch (command->open_client_session.login_type) { case TF_LOGIN_PUBLIC: /* Nothing to do */ break; case TF_LOGIN_USER: /* * Send the EUID of the calling application in the login data. * Update message size. */ *(u32 *) &command->open_client_session.login_data = current_euid(); #ifndef CONFIG_ANDROID command->open_client_session.login_type = (u32) TF_LOGIN_USER_LINUX_EUID; #else command->open_client_session.login_type = (u32) TF_LOGIN_USER_ANDROID_EUID; #endif /* Added one word */ command->open_client_session.message_size += 1; break; case TF_LOGIN_GROUP: { /* Check requested GID */ gid_t requested_gid = *(u32 *) command->open_client_session.login_data; if (!tf_check_gid(requested_gid)) { dprintk(KERN_ERR "tf_open_client_session(%p) " "TF_LOGIN_GROUP: requested GID (0x%x) does " "not match real eGID (0x%x)" "or any of the supplementary GIDs\n", connection, requested_gid, current_egid()); error = -EACCES; goto error; } #ifndef CONFIG_ANDROID command->open_client_session.login_type = TF_LOGIN_GROUP_LINUX_GID; #else command->open_client_session.login_type = TF_LOGIN_GROUP_ANDROID_GID; #endif command->open_client_session.message_size += 1; /* GID */ break; } #ifndef CONFIG_ANDROID case TF_LOGIN_APPLICATION: { /* * Compute SHA-1 hash of the application fully-qualified path * name. Truncate the hash to 16 bytes and send it as login * data. Update message size. */ u8 pSHA1Hash[SHA1_DIGEST_SIZE]; error = tf_hash_application_path_and_data(pSHA1Hash, NULL, 0); if (error != 0) { dprintk(KERN_ERR "tf_open_client_session: " "error in tf_hash_application_path_and_data\n"); goto error; } memcpy(&command->open_client_session.login_data, pSHA1Hash, 16); command->open_client_session.login_type = TF_LOGIN_APPLICATION_LINUX_PATH_SHA1_HASH; /* 16 bytes */ command->open_client_session.message_size += 4; break; } #else case TF_LOGIN_APPLICATION: /* * Send the real UID of the calling application in the login * data. Update message size. */ *(u32 *) &command->open_client_session.login_data = current_uid(); command->open_client_session.login_type = (u32) TF_LOGIN_APPLICATION_ANDROID_UID; /* Added one word */ command->open_client_session.message_size += 1; break; #endif #ifndef CONFIG_ANDROID case TF_LOGIN_APPLICATION_USER: { /* * Compute SHA-1 hash of the concatenation of the application * fully-qualified path name and the EUID of the calling * application. Truncate the hash to 16 bytes and send it as * login data. Update message size. */ u8 pSHA1Hash[SHA1_DIGEST_SIZE]; error = tf_hash_application_path_and_data(pSHA1Hash, (u8 *) &(current_euid()), sizeof(current_euid())); if (error != 0) { dprintk(KERN_ERR "tf_open_client_session: " "error in tf_hash_application_path_and_data\n"); goto error; } memcpy(&command->open_client_session.login_data, pSHA1Hash, 16); command->open_client_session.login_type = TF_LOGIN_APPLICATION_USER_LINUX_PATH_EUID_SHA1_HASH; /* 16 bytes */ command->open_client_session.message_size += 4; break; } #else case TF_LOGIN_APPLICATION_USER: /* * Send the real UID and the EUID of the calling application in * the login data. Update message size. */ *(u32 *) &command->open_client_session.login_data = current_uid(); *(u32 *) &command->open_client_session.login_data[4] = current_euid(); command->open_client_session.login_type = TF_LOGIN_APPLICATION_USER_ANDROID_UID_EUID; /* Added two words */ command->open_client_session.message_size += 2; break; #endif #ifndef CONFIG_ANDROID case TF_LOGIN_APPLICATION_GROUP: { /* * Check requested GID. Compute SHA-1 hash of the concatenation * of the application fully-qualified path name and the * requested GID. Update message size */ gid_t requested_gid; u8 pSHA1Hash[SHA1_DIGEST_SIZE]; requested_gid = *(u32 *) &command->open_client_session. login_data; if (!tf_check_gid(requested_gid)) { dprintk(KERN_ERR "tf_open_client_session(%p) " "TF_LOGIN_APPLICATION_GROUP: requested GID (0x%x) " "does not match real eGID (0x%x)" "or any of the supplementary GIDs\n", connection, requested_gid, current_egid()); error = -EACCES; goto error; } error = tf_hash_application_path_and_data(pSHA1Hash, &requested_gid, sizeof(u32)); if (error != 0) { dprintk(KERN_ERR "tf_open_client_session: " "error in tf_hash_application_path_and_data\n"); goto error; } memcpy(&command->open_client_session.login_data, pSHA1Hash, 16); command->open_client_session.login_type = TF_LOGIN_APPLICATION_GROUP_LINUX_PATH_GID_SHA1_HASH; /* 16 bytes */ command->open_client_session.message_size += 4; break; } #else case TF_LOGIN_APPLICATION_GROUP: { /* * Check requested GID. Send the real UID and the requested GID * in the login data. Update message size. */ gid_t requested_gid; requested_gid = *(u32 *) &command->open_client_session. login_data; if (!tf_check_gid(requested_gid)) { dprintk(KERN_ERR "tf_open_client_session(%p) " "TF_LOGIN_APPLICATION_GROUP: requested GID (0x%x) " "does not match real eGID (0x%x)" "or any of the supplementary GIDs\n", connection, requested_gid, current_egid()); error = -EACCES; goto error; } *(u32 *) &command->open_client_session.login_data = current_uid(); *(u32 *) &command->open_client_session.login_data[4] = requested_gid; command->open_client_session.login_type = TF_LOGIN_APPLICATION_GROUP_ANDROID_UID_GID; /* Added two words */ command->open_client_session.message_size += 2; break; } #endif case TF_LOGIN_PRIVILEGED: /* A privileged login may be performed only on behalf of the kernel itself or on behalf of a process with euid=0 or egid=0 or euid=system or egid=system. */ if (connection->owner == TF_CONNECTION_OWNER_KERNEL) { dprintk(KERN_DEBUG "tf_open_client_session: " "TF_LOGIN_PRIVILEGED for kernel API\n"); } else if ((current_euid() != TF_PRIVILEGED_UID_GID) && (current_egid() != TF_PRIVILEGED_UID_GID) && (current_euid() != 0) && (current_egid() != 0)) { dprintk(KERN_ERR "tf_open_client_session: " " user %d, group %d not allowed to open " "session with TF_LOGIN_PRIVILEGED\n", current_euid(), current_egid()); error = -EACCES; goto error; } else { dprintk(KERN_DEBUG "tf_open_client_session: " "TF_LOGIN_PRIVILEGED for %u:%u\n", current_euid(), current_egid()); } command->open_client_session.login_type = TF_LOGIN_PRIVILEGED; break; case TF_LOGIN_AUTHENTICATION: { /* * Compute SHA-1 hash of the application binary * Send this hash as the login data (20 bytes) */ u8 *hash; hash = &(command->open_client_session.login_data[0]); error = tf_get_current_process_hash(hash); if (error != 0) { dprintk(KERN_ERR "tf_open_client_session: " "error in tf_get_current_process_hash\n"); goto error; } command->open_client_session.login_type = TF_LOGIN_AUTHENTICATION_BINARY_SHA1_HASH; /* 20 bytes */ command->open_client_session.message_size += 5; break; } case TF_LOGIN_PRIVILEGED_KERNEL: /* A kernel login may be performed only on behalf of the kernel itself. */ if (connection->owner == TF_CONNECTION_OWNER_KERNEL) { dprintk(KERN_DEBUG "tf_open_client_session: " "TF_LOGIN_PRIVILEGED_KERNEL for kernel API\n"); command->open_client_session.login_type = TF_LOGIN_PRIVILEGED_KERNEL; } else { dprintk(KERN_ERR "tf_open_client_session: " " user %d, group %d not allowed to open " "session with TF_LOGIN_PRIVILEGED_KERNEL\n", current_euid(), current_egid()); error = -EACCES; goto error; } command->open_client_session.login_type = TF_LOGIN_PRIVILEGED_KERNEL; break; default: dprintk(KERN_ERR "tf_open_client_session: " "unknown login_type(%08X)\n", command->open_client_session.login_type); error = -EOPNOTSUPP; goto error; } /* Map the temporary memory references */ for (i = 0; i < 4; i++) { int param_type; param_type = TF_GET_PARAM_TYPE( command->open_client_session.param_types, i); if ((param_type & (TF_PARAM_TYPE_MEMREF_FLAG | TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG)) == TF_PARAM_TYPE_MEMREF_FLAG) { /* Map temp mem ref */ error = tf_map_temp_shmem(connection, &command->open_client_session. params[i].temp_memref, param_type, &shmem_desc[i]); if (error != 0) { dprintk(KERN_ERR "tf_open_client_session: " "unable to map temporary memory block " "(%08X)\n", error); goto error; } } } /* Fill the handle of the Device Context */ command->open_client_session.device_context = connection->device_context; error = tf_send_receive( &connection->dev->sm, command, answer, connection, true); error: /* Unmap the temporary memory references */ for (i = 0; i < 4; i++) if (shmem_desc[i] != NULL) tf_unmap_shmem(connection, shmem_desc[i], 0); if (error != 0) dprintk(KERN_ERR "tf_open_client_session returns %d\n", error); else dprintk(KERN_ERR "tf_open_client_session returns " "error_code 0x%08X\n", answer->open_client_session.error_code); return error; }
int tf_create_device_context( struct tf_connection *connection) { union tf_command command; union tf_answer answer; int error = 0; dprintk(KERN_INFO "tf_create_device_context(%p)\n", connection); command.create_device_context.message_type = TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT; command.create_device_context.message_size = (sizeof(struct tf_command_create_device_context) - sizeof(struct tf_command_header))/sizeof(u32); command.create_device_context.operation_id = (u32) &answer; command.create_device_context.device_context_id = (u32) connection; error = tf_send_receive( &connection->dev->sm, &command, &answer, connection, true); if ((error != 0) || (answer.create_device_context.error_code != S_SUCCESS)) goto error; /* * CREATE_DEVICE_CONTEXT succeeded, * store device context handler and update connection status */ connection->device_context = answer.create_device_context.device_context; spin_lock(&(connection->state_lock)); connection->state = TF_CONN_STATE_VALID_DEVICE_CONTEXT; spin_unlock(&(connection->state_lock)); /* successful completion */ dprintk(KERN_INFO "tf_create_device_context(%p):" " device_context=0x%08x\n", connection, answer.create_device_context.device_context); return 0; error: if (error != 0) { dprintk(KERN_ERR "tf_create_device_context failed with " "error %d\n", error); } else { /* * We sent a DeviceCreateContext. The state is now * TF_CONN_STATE_CREATE_DEVICE_CONTEXT_SENT It has to be * reset if we ever want to send a DeviceCreateContext again */ spin_lock(&(connection->state_lock)); connection->state = TF_CONN_STATE_NO_DEVICE_CONTEXT; spin_unlock(&(connection->state_lock)); dprintk(KERN_ERR "tf_create_device_context failed with " "error_code 0x%08X\n", answer.create_device_context.error_code); if (answer.create_device_context.error_code == S_ERROR_OUT_OF_MEMORY) error = -ENOMEM; else error = -EFAULT; } return error; }
/* * Destroys a device context from the Secure World */ int tf_destroy_device_context( struct tf_connection *connection) { int error; /* * AFY: better use the specialized tf_command_destroy_device_context * structure: this will save stack */ union tf_command command; union tf_answer answer; dprintk(KERN_INFO "tf_destroy_device_context(%p)\n", connection); BUG_ON(connection == NULL); command.header.message_type = TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT; command.header.message_size = (sizeof(struct tf_command_destroy_device_context) - sizeof(struct tf_command_header))/sizeof(u32); /* * fill in the device context handler * it is guarantied that the first shared memory descriptor describes * the device context */ command.destroy_device_context.device_context = connection->device_context; error = tf_send_receive( &connection->dev->sm, &command, &answer, connection, false); if ((error != 0) || (answer.destroy_device_context.error_code != S_SUCCESS)) goto error; spin_lock(&(connection->state_lock)); connection->state = TF_CONN_STATE_NO_DEVICE_CONTEXT; spin_unlock(&(connection->state_lock)); /* successful completion */ dprintk(KERN_INFO "tf_destroy_device_context(%p)\n", connection); return 0; error: if (error != 0) { dprintk(KERN_ERR "tf_destroy_device_context failed with " "error %d\n", error); } else { dprintk(KERN_ERR "tf_destroy_device_context failed with " "error_code 0x%08X\n", answer.destroy_device_context.error_code); if (answer.destroy_device_context.error_code == S_ERROR_OUT_OF_MEMORY) error = -ENOMEM; else error = -EFAULT; } return error; }
/* * Invokes a client command to the Secure World */ int tf_invoke_client_command( struct tf_connection *connection, union tf_command *command, union tf_answer *answer) { int error = 0; struct tf_shmem_desc *shmem_desc[4] = {NULL}; int i; #ifdef CONFIG_TF_ION struct ion_handle *new_handle = NULL; #endif /* CONFIG_TF_ION */ dprintk(KERN_INFO "tf_invoke_client_command(%p)\n", connection); command->release_shared_memory.message_size = (sizeof(struct tf_command_invoke_client_command) - sizeof(struct tf_command_header)) / 4; #ifdef CONFIG_TF_ZEBRA error = tf_crypto_try_shortcuted_update(connection, (struct tf_command_invoke_client_command *) command, (struct tf_answer_invoke_client_command *) answer); if (error == 0) return error; #endif /* Map the tmprefs */ for (i = 0; i < 4; i++) { int param_type = TF_GET_PARAM_TYPE( command->invoke_client_command.param_types, i); if ((param_type & (TF_PARAM_TYPE_MEMREF_FLAG | TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG)) == TF_PARAM_TYPE_MEMREF_FLAG) { /* A temporary memref: map it */ error = tf_map_temp_shmem(connection, &command->invoke_client_command. params[i].temp_memref, param_type, &shmem_desc[i]); if (error != 0) { dprintk(KERN_ERR "tf_invoke_client_command: " "unable to map temporary memory " "block\n (%08X)", error); goto error; } } #ifdef CONFIG_TF_ION else if (param_type == TF_PARAM_TYPE_MEMREF_ION_HANDLE) { struct tf_command_invoke_client_command *invoke; ion_phys_addr_t ion_addr; size_t ion_len; struct ion_buffer *buffer; if (connection->ion_client == NULL) { connection->ion_client = ion_client_create( zebra_ion_device, (1 << ION_HEAP_TYPE_CARVEOUT), "tf"); } if (connection->ion_client == NULL) { dprintk(KERN_ERR "%s(%p): " "unable to create ion client\n", __func__, connection); error = -EFAULT; goto error; } invoke = &command->invoke_client_command; dprintk(KERN_INFO "ion_handle %x", invoke->params[i].value.a); buffer = ion_share(connection->ion_client, (struct ion_handle *)invoke->params[i].value.a); if (buffer == NULL) { dprintk(KERN_ERR "%s(%p): " "unable to share ion handle\n", __func__, connection); error = -EFAULT; goto error; } dprintk(KERN_INFO "ion_buffer %p", buffer); new_handle = ion_import(connection->ion_client, buffer); if (new_handle == NULL) { dprintk(KERN_ERR "%s(%p): " "unable to import ion buffer\n", __func__, connection); error = -EFAULT; goto error; } dprintk(KERN_INFO "new_handle %x", new_handle); error = ion_phys(connection->ion_client, new_handle, &ion_addr, &ion_len); if (error) { dprintk(KERN_ERR "%s: unable to convert ion handle " "0x%08X (error code 0x%08X)\n", __func__, new_handle, error); error = -EINVAL; goto error; } dprintk(KERN_INFO "%s: handle=0x%08x phys_add=0x%08x length=0x%08x\n", __func__, invoke->params[i].value.a, ion_addr, ion_len); invoke->params[i].value.a = (u32) ion_addr; invoke->params[i].value.b = (u32) ion_len; invoke->param_types &= ~((0xF) << (4*i)); invoke->param_types |= TF_PARAM_TYPE_VALUE_INPUT << (4*i); } #endif /* CONFIG_TF_ION */ } command->invoke_client_command.device_context = connection->device_context; error = tf_send_receive(&connection->dev->sm, command, answer, connection, true); error: #ifdef CONFIG_TF_ION if (new_handle != NULL) ion_free(connection->ion_client, new_handle); #endif /* CONFIG_TF_ION */ /* Unmap de temp mem refs */ for (i = 0; i < 4; i++) { if (shmem_desc[i] != NULL) { dprintk(KERN_INFO "tf_invoke_client_command: " "UnMatemp_memref %d\n ", i); tf_unmap_shmem(connection, shmem_desc[i], 0); } } if (error != 0) dprintk(KERN_ERR "tf_invoke_client_command returns %d\n", error); else dprintk(KERN_ERR "tf_invoke_client_command returns " "error_code 0x%08X\n", answer->invoke_client_command.error_code); return error; }
/* * 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; }