diff options
| author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
|---|---|---|
| committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-01-22 10:38:37 -0500 |
| commit | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (patch) | |
| tree | a57612d1888735a2ec7972891b68c1ac5ec8faea /security | |
| parent | 8dea78da5cee153b8af9c07a2745f6c55057fe12 (diff) | |
Diffstat (limited to 'security')
| -rw-r--r-- | security/integrity/ima/ima_iint.c | 169 | ||||
| -rw-r--r-- | security/keys/ecryptfs_format.c | 81 | ||||
| -rw-r--r-- | security/keys/ecryptfs_format.h | 30 | ||||
| -rw-r--r-- | security/keys/encrypted.c | 1049 | ||||
| -rw-r--r-- | security/keys/encrypted.h | 54 | ||||
| -rw-r--r-- | security/tf_driver/Kconfig | 8 | ||||
| -rw-r--r-- | security/tf_driver/Makefile | 36 | ||||
| -rw-r--r-- | security/tf_driver/s_version.h | 92 | ||||
| -rw-r--r-- | security/tf_driver/tf_comm.c | 1745 | ||||
| -rw-r--r-- | security/tf_driver/tf_comm.h | 202 | ||||
| -rw-r--r-- | security/tf_driver/tf_comm_tz.c | 885 | ||||
| -rw-r--r-- | security/tf_driver/tf_conn.c | 1574 | ||||
| -rw-r--r-- | security/tf_driver/tf_conn.h | 106 | ||||
| -rw-r--r-- | security/tf_driver/tf_defs.h | 538 | ||||
| -rw-r--r-- | security/tf_driver/tf_device.c | 796 | ||||
| -rw-r--r-- | security/tf_driver/tf_protocol.h | 690 | ||||
| -rw-r--r-- | security/tf_driver/tf_util.c | 1143 | ||||
| -rw-r--r-- | security/tf_driver/tf_util.h | 122 |
18 files changed, 9320 insertions, 0 deletions
diff --git a/security/integrity/ima/ima_iint.c b/security/integrity/ima/ima_iint.c new file mode 100644 index 00000000000..4ae73040ab7 --- /dev/null +++ b/security/integrity/ima/ima_iint.c | |||
| @@ -0,0 +1,169 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2008 IBM Corporation | ||
| 3 | * | ||
| 4 | * Authors: | ||
| 5 | * Mimi Zohar <zohar@us.ibm.com> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License as | ||
| 9 | * published by the Free Software Foundation, version 2 of the | ||
| 10 | * License. | ||
| 11 | * | ||
| 12 | * File: ima_iint.c | ||
| 13 | * - implements the IMA hooks: ima_inode_alloc, ima_inode_free | ||
| 14 | * - cache integrity information associated with an inode | ||
| 15 | * using a rbtree tree. | ||
| 16 | */ | ||
| 17 | #include <linux/slab.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/spinlock.h> | ||
| 20 | #include <linux/rbtree.h> | ||
| 21 | #include "ima.h" | ||
| 22 | |||
| 23 | static struct rb_root ima_iint_tree = RB_ROOT; | ||
| 24 | static DEFINE_SPINLOCK(ima_iint_lock); | ||
| 25 | static struct kmem_cache *iint_cache __read_mostly; | ||
| 26 | |||
| 27 | int iint_initialized = 0; | ||
| 28 | |||
| 29 | /* | ||
| 30 | * __ima_iint_find - return the iint associated with an inode | ||
| 31 | */ | ||
| 32 | static struct ima_iint_cache *__ima_iint_find(struct inode *inode) | ||
| 33 | { | ||
| 34 | struct ima_iint_cache *iint; | ||
| 35 | struct rb_node *n = ima_iint_tree.rb_node; | ||
| 36 | |||
| 37 | assert_spin_locked(&ima_iint_lock); | ||
| 38 | |||
| 39 | while (n) { | ||
| 40 | iint = rb_entry(n, struct ima_iint_cache, rb_node); | ||
| 41 | |||
| 42 | if (inode < iint->inode) | ||
| 43 | n = n->rb_left; | ||
| 44 | else if (inode > iint->inode) | ||
| 45 | n = n->rb_right; | ||
| 46 | else | ||
| 47 | break; | ||
| 48 | } | ||
| 49 | if (!n) | ||
| 50 | return NULL; | ||
| 51 | |||
| 52 | return iint; | ||
| 53 | } | ||
| 54 | |||
| 55 | /* | ||
| 56 | * ima_iint_find - return the iint associated with an inode | ||
| 57 | */ | ||
| 58 | struct ima_iint_cache *ima_iint_find(struct inode *inode) | ||
| 59 | { | ||
| 60 | struct ima_iint_cache *iint; | ||
| 61 | |||
| 62 | if (!IS_IMA(inode)) | ||
| 63 | return NULL; | ||
| 64 | |||
| 65 | spin_lock(&ima_iint_lock); | ||
| 66 | iint = __ima_iint_find(inode); | ||
| 67 | spin_unlock(&ima_iint_lock); | ||
| 68 | |||
| 69 | return iint; | ||
| 70 | } | ||
| 71 | |||
| 72 | static void iint_free(struct ima_iint_cache *iint) | ||
| 73 | { | ||
| 74 | iint->version = 0; | ||
| 75 | iint->flags = 0UL; | ||
| 76 | kmem_cache_free(iint_cache, iint); | ||
| 77 | } | ||
| 78 | |||
| 79 | /** | ||
| 80 | * ima_inode_alloc - allocate an iint associated with an inode | ||
| 81 | * @inode: pointer to the inode | ||
| 82 | */ | ||
| 83 | int ima_inode_alloc(struct inode *inode) | ||
| 84 | { | ||
| 85 | struct rb_node **p; | ||
| 86 | struct rb_node *new_node, *parent = NULL; | ||
| 87 | struct ima_iint_cache *new_iint, *test_iint; | ||
| 88 | int rc; | ||
| 89 | |||
| 90 | new_iint = kmem_cache_alloc(iint_cache, GFP_NOFS); | ||
| 91 | if (!new_iint) | ||
| 92 | return -ENOMEM; | ||
| 93 | |||
| 94 | new_iint->inode = inode; | ||
| 95 | new_node = &new_iint->rb_node; | ||
| 96 | |||
| 97 | mutex_lock(&inode->i_mutex); /* i_flags */ | ||
| 98 | spin_lock(&ima_iint_lock); | ||
| 99 | |||
| 100 | p = &ima_iint_tree.rb_node; | ||
| 101 | while (*p) { | ||
| 102 | parent = *p; | ||
| 103 | test_iint = rb_entry(parent, struct ima_iint_cache, rb_node); | ||
| 104 | |||
| 105 | rc = -EEXIST; | ||
| 106 | if (inode < test_iint->inode) | ||
| 107 | p = &(*p)->rb_left; | ||
| 108 | else if (inode > test_iint->inode) | ||
| 109 | p = &(*p)->rb_right; | ||
| 110 | else | ||
| 111 | goto out_err; | ||
| 112 | } | ||
| 113 | |||
| 114 | inode->i_flags |= S_IMA; | ||
| 115 | rb_link_node(new_node, parent, p); | ||
| 116 | rb_insert_color(new_node, &ima_iint_tree); | ||
| 117 | |||
| 118 | spin_unlock(&ima_iint_lock); | ||
| 119 | mutex_unlock(&inode->i_mutex); /* i_flags */ | ||
| 120 | |||
| 121 | return 0; | ||
| 122 | out_err: | ||
| 123 | spin_unlock(&ima_iint_lock); | ||
| 124 | mutex_unlock(&inode->i_mutex); /* i_flags */ | ||
| 125 | iint_free(new_iint); | ||
| 126 | |||
| 127 | return rc; | ||
| 128 | } | ||
| 129 | |||
| 130 | /** | ||
| 131 | * ima_inode_free - called on security_inode_free | ||
| 132 | * @inode: pointer to the inode | ||
| 133 | * | ||
| 134 | * Free the integrity information(iint) associated with an inode. | ||
| 135 | */ | ||
| 136 | void ima_inode_free(struct inode *inode) | ||
| 137 | { | ||
| 138 | struct ima_iint_cache *iint; | ||
| 139 | |||
| 140 | if (!IS_IMA(inode)) | ||
| 141 | return; | ||
| 142 | |||
| 143 | spin_lock(&ima_iint_lock); | ||
| 144 | iint = __ima_iint_find(inode); | ||
| 145 | rb_erase(&iint->rb_node, &ima_iint_tree); | ||
| 146 | spin_unlock(&ima_iint_lock); | ||
| 147 | |||
| 148 | iint_free(iint); | ||
| 149 | } | ||
| 150 | |||
| 151 | static void init_once(void *foo) | ||
| 152 | { | ||
| 153 | struct ima_iint_cache *iint = foo; | ||
| 154 | |||
| 155 | memset(iint, 0, sizeof *iint); | ||
| 156 | iint->version = 0; | ||
| 157 | iint->flags = 0UL; | ||
| 158 | mutex_init(&iint->mutex); | ||
| 159 | } | ||
| 160 | |||
| 161 | static int __init ima_iintcache_init(void) | ||
| 162 | { | ||
| 163 | iint_cache = | ||
| 164 | kmem_cache_create("iint_cache", sizeof(struct ima_iint_cache), 0, | ||
| 165 | SLAB_PANIC, init_once); | ||
| 166 | iint_initialized = 1; | ||
| 167 | return 0; | ||
| 168 | } | ||
| 169 | security_initcall(ima_iintcache_init); | ||
diff --git a/security/keys/ecryptfs_format.c b/security/keys/ecryptfs_format.c new file mode 100644 index 00000000000..6daa3b6ff9e --- /dev/null +++ b/security/keys/ecryptfs_format.c | |||
| @@ -0,0 +1,81 @@ | |||
| 1 | /* | ||
| 2 | * ecryptfs_format.c: helper functions for the encrypted key type | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006 International Business Machines Corp. | ||
| 5 | * Copyright (C) 2010 Politecnico di Torino, Italy | ||
| 6 | * TORSEC group -- http://security.polito.it | ||
| 7 | * | ||
| 8 | * Authors: | ||
| 9 | * Michael A. Halcrow <mahalcro@us.ibm.com> | ||
| 10 | * Tyler Hicks <tyhicks@ou.edu> | ||
| 11 | * Roberto Sassu <roberto.sassu@polito.it> | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License as published by | ||
| 15 | * the Free Software Foundation, version 2 of the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #include <linux/module.h> | ||
| 19 | #include "ecryptfs_format.h" | ||
| 20 | |||
| 21 | u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok) | ||
| 22 | { | ||
| 23 | return auth_tok->token.password.session_key_encryption_key; | ||
| 24 | } | ||
| 25 | EXPORT_SYMBOL(ecryptfs_get_auth_tok_key); | ||
| 26 | |||
| 27 | /* | ||
| 28 | * ecryptfs_get_versions() | ||
| 29 | * | ||
| 30 | * Source code taken from the software 'ecryptfs-utils' version 83. | ||
| 31 | * | ||
| 32 | */ | ||
| 33 | void ecryptfs_get_versions(int *major, int *minor, int *file_version) | ||
| 34 | { | ||
| 35 | *major = ECRYPTFS_VERSION_MAJOR; | ||
| 36 | *minor = ECRYPTFS_VERSION_MINOR; | ||
| 37 | if (file_version) | ||
| 38 | *file_version = ECRYPTFS_SUPPORTED_FILE_VERSION; | ||
| 39 | } | ||
| 40 | EXPORT_SYMBOL(ecryptfs_get_versions); | ||
| 41 | |||
| 42 | /* | ||
| 43 | * ecryptfs_fill_auth_tok - fill the ecryptfs_auth_tok structure | ||
| 44 | * | ||
| 45 | * Fill the ecryptfs_auth_tok structure with required ecryptfs data. | ||
| 46 | * The source code is inspired to the original function generate_payload() | ||
| 47 | * shipped with the software 'ecryptfs-utils' version 83. | ||
| 48 | * | ||
| 49 | */ | ||
| 50 | int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok, | ||
| 51 | const char *key_desc) | ||
| 52 | { | ||
| 53 | int major, minor; | ||
| 54 | |||
| 55 | ecryptfs_get_versions(&major, &minor, NULL); | ||
| 56 | auth_tok->version = (((uint16_t)(major << 8) & 0xFF00) | ||
| 57 | | ((uint16_t)minor & 0x00FF)); | ||
| 58 | auth_tok->token_type = ECRYPTFS_PASSWORD; | ||
| 59 | strncpy((char *)auth_tok->token.password.signature, key_desc, | ||
| 60 | ECRYPTFS_PASSWORD_SIG_SIZE); | ||
| 61 | auth_tok->token.password.session_key_encryption_key_bytes = | ||
| 62 | ECRYPTFS_MAX_KEY_BYTES; | ||
| 63 | /* | ||
| 64 | * Removed auth_tok->token.password.salt and | ||
| 65 | * auth_tok->token.password.session_key_encryption_key | ||
| 66 | * initialization from the original code | ||
| 67 | */ | ||
| 68 | /* TODO: Make the hash parameterizable via policy */ | ||
| 69 | auth_tok->token.password.flags |= | ||
| 70 | ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET; | ||
| 71 | /* The kernel code will encrypt the session key. */ | ||
| 72 | auth_tok->session_key.encrypted_key[0] = 0; | ||
| 73 | auth_tok->session_key.encrypted_key_size = 0; | ||
| 74 | /* Default; subject to change by kernel eCryptfs */ | ||
| 75 | auth_tok->token.password.hash_algo = PGP_DIGEST_ALGO_SHA512; | ||
| 76 | auth_tok->token.password.flags &= ~(ECRYPTFS_PERSISTENT_PASSWORD); | ||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | EXPORT_SYMBOL(ecryptfs_fill_auth_tok); | ||
| 80 | |||
| 81 | MODULE_LICENSE("GPL"); | ||
diff --git a/security/keys/ecryptfs_format.h b/security/keys/ecryptfs_format.h new file mode 100644 index 00000000000..40294de238b --- /dev/null +++ b/security/keys/ecryptfs_format.h | |||
| @@ -0,0 +1,30 @@ | |||
| 1 | /* | ||
| 2 | * ecryptfs_format.h: helper functions for the encrypted key type | ||
| 3 | * | ||
| 4 | * Copyright (C) 2006 International Business Machines Corp. | ||
| 5 | * Copyright (C) 2010 Politecnico di Torino, Italy | ||
| 6 | * TORSEC group -- http://security.polito.it | ||
| 7 | * | ||
| 8 | * Authors: | ||
| 9 | * Michael A. Halcrow <mahalcro@us.ibm.com> | ||
| 10 | * Tyler Hicks <tyhicks@ou.edu> | ||
| 11 | * Roberto Sassu <roberto.sassu@polito.it> | ||
| 12 | * | ||
| 13 | * This program is free software; you can redistribute it and/or modify | ||
| 14 | * it under the terms of the GNU General Public License as published by | ||
| 15 | * the Free Software Foundation, version 2 of the License. | ||
| 16 | */ | ||
| 17 | |||
| 18 | #ifndef __KEYS_ECRYPTFS_H | ||
| 19 | #define __KEYS_ECRYPTFS_H | ||
| 20 | |||
| 21 | #include <linux/ecryptfs.h> | ||
| 22 | |||
| 23 | #define PGP_DIGEST_ALGO_SHA512 10 | ||
| 24 | |||
| 25 | u8 *ecryptfs_get_auth_tok_key(struct ecryptfs_auth_tok *auth_tok); | ||
| 26 | void ecryptfs_get_versions(int *major, int *minor, int *file_version); | ||
| 27 | int ecryptfs_fill_auth_tok(struct ecryptfs_auth_tok *auth_tok, | ||
| 28 | const char *key_desc); | ||
| 29 | |||
| 30 | #endif /* __KEYS_ECRYPTFS_H */ | ||
diff --git a/security/keys/encrypted.c b/security/keys/encrypted.c new file mode 100644 index 00000000000..e7eca9ec4c6 --- /dev/null +++ b/security/keys/encrypted.c | |||
| @@ -0,0 +1,1049 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2010 IBM Corporation | ||
| 3 | * Copyright (C) 2010 Politecnico di Torino, Italy | ||
| 4 | * TORSEC group -- http://security.polito.it | ||
| 5 | * | ||
| 6 | * Authors: | ||
| 7 | * Mimi Zohar <zohar@us.ibm.com> | ||
| 8 | * Roberto Sassu <roberto.sassu@polito.it> | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or modify | ||
| 11 | * it under the terms of the GNU General Public License as published by | ||
| 12 | * the Free Software Foundation, version 2 of the License. | ||
| 13 | * | ||
| 14 | * See Documentation/security/keys-trusted-encrypted.txt | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/uaccess.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/init.h> | ||
| 20 | #include <linux/slab.h> | ||
| 21 | #include <linux/parser.h> | ||
| 22 | #include <linux/string.h> | ||
| 23 | #include <linux/err.h> | ||
| 24 | #include <keys/user-type.h> | ||
| 25 | #include <keys/trusted-type.h> | ||
| 26 | #include <keys/encrypted-type.h> | ||
| 27 | #include <linux/key-type.h> | ||
| 28 | #include <linux/random.h> | ||
| 29 | #include <linux/rcupdate.h> | ||
| 30 | #include <linux/scatterlist.h> | ||
| 31 | #include <linux/crypto.h> | ||
| 32 | #include <linux/ctype.h> | ||
| 33 | #include <crypto/hash.h> | ||
| 34 | #include <crypto/sha.h> | ||
| 35 | #include <crypto/aes.h> | ||
| 36 | |||
| 37 | #include "encrypted.h" | ||
| 38 | #include "ecryptfs_format.h" | ||
| 39 | |||
| 40 | static const char KEY_TRUSTED_PREFIX[] = "trusted:"; | ||
| 41 | static const char KEY_USER_PREFIX[] = "user:"; | ||
| 42 | static const char hash_alg[] = "sha256"; | ||
| 43 | static const char hmac_alg[] = "hmac(sha256)"; | ||
| 44 | static const char blkcipher_alg[] = "cbc(aes)"; | ||
| 45 | static const char key_format_default[] = "default"; | ||
| 46 | static const char key_format_ecryptfs[] = "ecryptfs"; | ||
| 47 | static unsigned int ivsize; | ||
| 48 | static int blksize; | ||
| 49 | |||
| 50 | #define KEY_TRUSTED_PREFIX_LEN (sizeof (KEY_TRUSTED_PREFIX) - 1) | ||
| 51 | #define KEY_USER_PREFIX_LEN (sizeof (KEY_USER_PREFIX) - 1) | ||
| 52 | #define KEY_ECRYPTFS_DESC_LEN 16 | ||
| 53 | #define HASH_SIZE SHA256_DIGEST_SIZE | ||
| 54 | #define MAX_DATA_SIZE 4096 | ||
| 55 | #define MIN_DATA_SIZE 20 | ||
| 56 | |||
| 57 | struct sdesc { | ||
| 58 | struct shash_desc shash; | ||
| 59 | char ctx[]; | ||
| 60 | }; | ||
| 61 | |||
| 62 | static struct crypto_shash *hashalg; | ||
| 63 | static struct crypto_shash *hmacalg; | ||
| 64 | |||
| 65 | enum { | ||
| 66 | Opt_err = -1, Opt_new, Opt_load, Opt_update | ||
| 67 | }; | ||
| 68 | |||
| 69 | enum { | ||
| 70 | Opt_error = -1, Opt_default, Opt_ecryptfs | ||
| 71 | }; | ||
| 72 | |||
| 73 | static const match_table_t key_format_tokens = { | ||
| 74 | {Opt_default, "default"}, | ||
| 75 | {Opt_ecryptfs, "ecryptfs"}, | ||
| 76 | {Opt_error, NULL} | ||
| 77 | }; | ||
| 78 | |||
| 79 | static const match_table_t key_tokens = { | ||
| 80 | {Opt_new, "new"}, | ||
| 81 | {Opt_load, "load"}, | ||
| 82 | {Opt_update, "update"}, | ||
| 83 | {Opt_err, NULL} | ||
| 84 | }; | ||
| 85 | |||
| 86 | static int aes_get_sizes(void) | ||
| 87 | { | ||
| 88 | struct crypto_blkcipher *tfm; | ||
| 89 | |||
| 90 | tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC); | ||
| 91 | if (IS_ERR(tfm)) { | ||
| 92 | pr_err("encrypted_key: failed to alloc_cipher (%ld)\n", | ||
| 93 | PTR_ERR(tfm)); | ||
| 94 | return PTR_ERR(tfm); | ||
| 95 | } | ||
| 96 | ivsize = crypto_blkcipher_ivsize(tfm); | ||
| 97 | blksize = crypto_blkcipher_blocksize(tfm); | ||
| 98 | crypto_free_blkcipher(tfm); | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | /* | ||
| 103 | * valid_ecryptfs_desc - verify the description of a new/loaded encrypted key | ||
| 104 | * | ||
| 105 | * The description of a encrypted key with format 'ecryptfs' must contain | ||
| 106 | * exactly 16 hexadecimal characters. | ||
| 107 | * | ||
| 108 | */ | ||
| 109 | static int valid_ecryptfs_desc(const char *ecryptfs_desc) | ||
| 110 | { | ||
| 111 | int i; | ||
| 112 | |||
| 113 | if (strlen(ecryptfs_desc) != KEY_ECRYPTFS_DESC_LEN) { | ||
| 114 | pr_err("encrypted_key: key description must be %d hexadecimal " | ||
| 115 | "characters long\n", KEY_ECRYPTFS_DESC_LEN); | ||
| 116 | return -EINVAL; | ||
| 117 | } | ||
| 118 | |||
| 119 | for (i = 0; i < KEY_ECRYPTFS_DESC_LEN; i++) { | ||
| 120 | if (!isxdigit(ecryptfs_desc[i])) { | ||
| 121 | pr_err("encrypted_key: key description must contain " | ||
| 122 | "only hexadecimal characters\n"); | ||
| 123 | return -EINVAL; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | |||
| 127 | return 0; | ||
| 128 | } | ||
| 129 | |||
| 130 | /* | ||
| 131 | * valid_master_desc - verify the 'key-type:desc' of a new/updated master-key | ||
| 132 | * | ||
| 133 | * key-type:= "trusted:" | "user:" | ||
| 134 | * desc:= master-key description | ||
| 135 | * | ||
| 136 | * Verify that 'key-type' is valid and that 'desc' exists. On key update, | ||
| 137 | * only the master key description is permitted to change, not the key-type. | ||
| 138 | * The key-type remains constant. | ||
| 139 | * | ||
| 140 | * On success returns 0, otherwise -EINVAL. | ||
| 141 | */ | ||
| 142 | static int valid_master_desc(const char *new_desc, const char *orig_desc) | ||
| 143 | { | ||
| 144 | if (!memcmp(new_desc, KEY_TRUSTED_PREFIX, KEY_TRUSTED_PREFIX_LEN)) { | ||
| 145 | if (strlen(new_desc) == KEY_TRUSTED_PREFIX_LEN) | ||
| 146 | goto out; | ||
| 147 | if (orig_desc) | ||
| 148 | if (memcmp(new_desc, orig_desc, KEY_TRUSTED_PREFIX_LEN)) | ||
| 149 | goto out; | ||
| 150 | } else if (!memcmp(new_desc, KEY_USER_PREFIX, KEY_USER_PREFIX_LEN)) { | ||
| 151 | if (strlen(new_desc) == KEY_USER_PREFIX_LEN) | ||
| 152 | goto out; | ||
| 153 | if (orig_desc) | ||
| 154 | if (memcmp(new_desc, orig_desc, KEY_USER_PREFIX_LEN)) | ||
| 155 | goto out; | ||
| 156 | } else | ||
| 157 | goto out; | ||
| 158 | return 0; | ||
| 159 | out: | ||
| 160 | return -EINVAL; | ||
| 161 | } | ||
| 162 | |||
| 163 | /* | ||
| 164 | * datablob_parse - parse the keyctl data | ||
| 165 | * | ||
| 166 | * datablob format: | ||
| 167 | * new [<format>] <master-key name> <decrypted data length> | ||
| 168 | * load [<format>] <master-key name> <decrypted data length> | ||
| 169 | * <encrypted iv + data> | ||
| 170 | * update <new-master-key name> | ||
| 171 | * | ||
| 172 | * Tokenizes a copy of the keyctl data, returning a pointer to each token, | ||
| 173 | * which is null terminated. | ||
| 174 | * | ||
| 175 | * On success returns 0, otherwise -EINVAL. | ||
| 176 | */ | ||
| 177 | static int datablob_parse(char *datablob, const char **format, | ||
| 178 | char **master_desc, char **decrypted_datalen, | ||
| 179 | char **hex_encoded_iv) | ||
| 180 | { | ||
| 181 | substring_t args[MAX_OPT_ARGS]; | ||
| 182 | int ret = -EINVAL; | ||
| 183 | int key_cmd; | ||
| 184 | int key_format; | ||
| 185 | char *p, *keyword; | ||
| 186 | |||
| 187 | keyword = strsep(&datablob, " \t"); | ||
| 188 | if (!keyword) { | ||
| 189 | pr_info("encrypted_key: insufficient parameters specified\n"); | ||
| 190 | return ret; | ||
| 191 | } | ||
| 192 | key_cmd = match_token(keyword, key_tokens, args); | ||
| 193 | |||
| 194 | /* Get optional format: default | ecryptfs */ | ||
| 195 | p = strsep(&datablob, " \t"); | ||
| 196 | if (!p) { | ||
| 197 | pr_err("encrypted_key: insufficient parameters specified\n"); | ||
| 198 | return ret; | ||
| 199 | } | ||
| 200 | |||
| 201 | key_format = match_token(p, key_format_tokens, args); | ||
| 202 | switch (key_format) { | ||
| 203 | case Opt_ecryptfs: | ||
| 204 | case Opt_default: | ||
| 205 | *format = p; | ||
| 206 | *master_desc = strsep(&datablob, " \t"); | ||
| 207 | break; | ||
| 208 | case Opt_error: | ||
| 209 | *master_desc = p; | ||
| 210 | break; | ||
| 211 | } | ||
| 212 | |||
| 213 | if (!*master_desc) { | ||
| 214 | pr_info("encrypted_key: master key parameter is missing\n"); | ||
| 215 | goto out; | ||
| 216 | } | ||
| 217 | |||
| 218 | if (valid_master_desc(*master_desc, NULL) < 0) { | ||
| 219 | pr_info("encrypted_key: master key parameter \'%s\' " | ||
| 220 | "is invalid\n", *master_desc); | ||
| 221 | goto out; | ||
| 222 | } | ||
| 223 | |||
| 224 | if (decrypted_datalen) { | ||
| 225 | *decrypted_datalen = strsep(&datablob, " \t"); | ||
| 226 | if (!*decrypted_datalen) { | ||
| 227 | pr_info("encrypted_key: keylen parameter is missing\n"); | ||
| 228 | goto out; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | |||
| 232 | switch (key_cmd) { | ||
| 233 | case Opt_new: | ||
| 234 | if (!decrypted_datalen) { | ||
| 235 | pr_info("encrypted_key: keyword \'%s\' not allowed " | ||
| 236 | "when called from .update method\n", keyword); | ||
| 237 | break; | ||
| 238 | } | ||
| 239 | ret = 0; | ||
| 240 | break; | ||
| 241 | case Opt_load: | ||
| 242 | if (!decrypted_datalen) { | ||
| 243 | pr_info("encrypted_key: keyword \'%s\' not allowed " | ||
| 244 | "when called from .update method\n", keyword); | ||
| 245 | break; | ||
| 246 | } | ||
| 247 | *hex_encoded_iv = strsep(&datablob, " \t"); | ||
| 248 | if (!*hex_encoded_iv) { | ||
| 249 | pr_info("encrypted_key: hex blob is missing\n"); | ||
| 250 | break; | ||
| 251 | } | ||
| 252 | ret = 0; | ||
| 253 | break; | ||
| 254 | case Opt_update: | ||
| 255 | if (decrypted_datalen) { | ||
| 256 | pr_info("encrypted_key: keyword \'%s\' not allowed " | ||
| 257 | "when called from .instantiate method\n", | ||
| 258 | keyword); | ||
| 259 | break; | ||
| 260 | } | ||
| 261 | ret = 0; | ||
| 262 | break; | ||
| 263 | case Opt_err: | ||
| 264 | pr_info("encrypted_key: keyword \'%s\' not recognized\n", | ||
| 265 | keyword); | ||
| 266 | break; | ||
| 267 | } | ||
| 268 | out: | ||
| 269 | return ret; | ||
| 270 | } | ||
| 271 | |||
| 272 | /* | ||
| 273 | * datablob_format - format as an ascii string, before copying to userspace | ||
| 274 | */ | ||
| 275 | static char *datablob_format(struct encrypted_key_payload *epayload, | ||
| 276 | size_t asciiblob_len) | ||
| 277 | { | ||
| 278 | char *ascii_buf, *bufp; | ||
| 279 | u8 *iv = epayload->iv; | ||
| 280 | int len; | ||
| 281 | int i; | ||
| 282 | |||
| 283 | ascii_buf = kmalloc(asciiblob_len + 1, GFP_KERNEL); | ||
| 284 | if (!ascii_buf) | ||
| 285 | goto out; | ||
| 286 | |||
| 287 | ascii_buf[asciiblob_len] = '\0'; | ||
| 288 | |||
| 289 | /* copy datablob master_desc and datalen strings */ | ||
| 290 | len = sprintf(ascii_buf, "%s %s %s ", epayload->format, | ||
| 291 | epayload->master_desc, epayload->datalen); | ||
| 292 | |||
| 293 | /* convert the hex encoded iv, encrypted-data and HMAC to ascii */ | ||
| 294 | bufp = &ascii_buf[len]; | ||
| 295 | for (i = 0; i < (asciiblob_len - len) / 2; i++) | ||
| 296 | bufp = pack_hex_byte(bufp, iv[i]); | ||
| 297 | out: | ||
| 298 | return ascii_buf; | ||
| 299 | } | ||
| 300 | |||
| 301 | /* | ||
| 302 | * request_trusted_key - request the trusted key | ||
| 303 | * | ||
| 304 | * Trusted keys are sealed to PCRs and other metadata. Although userspace | ||
| 305 | * manages both trusted/encrypted key-types, like the encrypted key type | ||
| 306 | * data, trusted key type data is not visible decrypted from userspace. | ||
| 307 | */ | ||
| 308 | static struct key *request_trusted_key(const char *trusted_desc, | ||
| 309 | u8 **master_key, size_t *master_keylen) | ||
| 310 | { | ||
| 311 | struct trusted_key_payload *tpayload; | ||
| 312 | struct key *tkey; | ||
| 313 | |||
| 314 | tkey = request_key(&key_type_trusted, trusted_desc, NULL); | ||
| 315 | if (IS_ERR(tkey)) | ||
| 316 | goto error; | ||
| 317 | |||
| 318 | down_read(&tkey->sem); | ||
| 319 | tpayload = rcu_dereference(tkey->payload.data); | ||
| 320 | *master_key = tpayload->key; | ||
| 321 | *master_keylen = tpayload->key_len; | ||
| 322 | error: | ||
| 323 | return tkey; | ||
| 324 | } | ||
| 325 | |||
| 326 | /* | ||
| 327 | * request_user_key - request the user key | ||
| 328 | * | ||
| 329 | * Use a user provided key to encrypt/decrypt an encrypted-key. | ||
| 330 | */ | ||
| 331 | static struct key *request_user_key(const char *master_desc, u8 **master_key, | ||
| 332 | size_t *master_keylen) | ||
| 333 | { | ||
| 334 | struct user_key_payload *upayload; | ||
| 335 | struct key *ukey; | ||
| 336 | |||
| 337 | ukey = request_key(&key_type_user, master_desc, NULL); | ||
| 338 | if (IS_ERR(ukey)) | ||
| 339 | goto error; | ||
| 340 | |||
| 341 | down_read(&ukey->sem); | ||
| 342 | upayload = rcu_dereference(ukey->payload.data); | ||
| 343 | *master_key = upayload->data; | ||
| 344 | *master_keylen = upayload->datalen; | ||
| 345 | error: | ||
| 346 | return ukey; | ||
| 347 | } | ||
| 348 | |||
| 349 | static struct sdesc *alloc_sdesc(struct crypto_shash *alg) | ||
| 350 | { | ||
| 351 | struct sdesc *sdesc; | ||
| 352 | int size; | ||
| 353 | |||
| 354 | size = sizeof(struct shash_desc) + crypto_shash_descsize(alg); | ||
| 355 | sdesc = kmalloc(size, GFP_KERNEL); | ||
| 356 | if (!sdesc) | ||
| 357 | return ERR_PTR(-ENOMEM); | ||
| 358 | sdesc->shash.tfm = alg; | ||
| 359 | sdesc->shash.flags = 0x0; | ||
| 360 | return sdesc; | ||
| 361 | } | ||
| 362 | |||
| 363 | static int calc_hmac(u8 *digest, const u8 *key, unsigned int keylen, | ||
| 364 | const u8 *buf, unsigned int buflen) | ||
| 365 | { | ||
| 366 | struct sdesc *sdesc; | ||
| 367 | int ret; | ||
| 368 | |||
| 369 | sdesc = alloc_sdesc(hmacalg); | ||
| 370 | if (IS_ERR(sdesc)) { | ||
| 371 | pr_info("encrypted_key: can't alloc %s\n", hmac_alg); | ||
| 372 | return PTR_ERR(sdesc); | ||
| 373 | } | ||
| 374 | |||
| 375 | ret = crypto_shash_setkey(hmacalg, key, keylen); | ||
| 376 | if (!ret) | ||
| 377 | ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest); | ||
| 378 | kfree(sdesc); | ||
| 379 | return ret; | ||
| 380 | } | ||
| 381 | |||
| 382 | static int calc_hash(u8 *digest, const u8 *buf, unsigned int buflen) | ||
| 383 | { | ||
| 384 | struct sdesc *sdesc; | ||
| 385 | int ret; | ||
| 386 | |||
| 387 | sdesc = alloc_sdesc(hashalg); | ||
| 388 | if (IS_ERR(sdesc)) { | ||
| 389 | pr_info("encrypted_key: can't alloc %s\n", hash_alg); | ||
| 390 | return PTR_ERR(sdesc); | ||
| 391 | } | ||
| 392 | |||
| 393 | ret = crypto_shash_digest(&sdesc->shash, buf, buflen, digest); | ||
| 394 | kfree(sdesc); | ||
| 395 | return ret; | ||
| 396 | } | ||
| 397 | |||
| 398 | enum derived_key_type { ENC_KEY, AUTH_KEY }; | ||
| 399 | |||
| 400 | /* Derive authentication/encryption key from trusted key */ | ||
| 401 | static int get_derived_key(u8 *derived_key, enum derived_key_type key_type, | ||
| 402 | const u8 *master_key, size_t master_keylen) | ||
| 403 | { | ||
| 404 | u8 *derived_buf; | ||
| 405 | unsigned int derived_buf_len; | ||
| 406 | int ret; | ||
| 407 | |||
| 408 | derived_buf_len = strlen("AUTH_KEY") + 1 + master_keylen; | ||
| 409 | if (derived_buf_len < HASH_SIZE) | ||
| 410 | derived_buf_len = HASH_SIZE; | ||
| 411 | |||
| 412 | derived_buf = kzalloc(derived_buf_len, GFP_KERNEL); | ||
| 413 | if (!derived_buf) { | ||
| 414 | pr_err("encrypted_key: out of memory\n"); | ||
| 415 | return -ENOMEM; | ||
| 416 | } | ||
| 417 | if (key_type) | ||
| 418 | strcpy(derived_buf, "AUTH_KEY"); | ||
| 419 | else | ||
| 420 | strcpy(derived_buf, "ENC_KEY"); | ||
| 421 | |||
| 422 | memcpy(derived_buf + strlen(derived_buf) + 1, master_key, | ||
| 423 | master_keylen); | ||
| 424 | ret = calc_hash(derived_key, derived_buf, derived_buf_len); | ||
| 425 | kfree(derived_buf); | ||
| 426 | return ret; | ||
| 427 | } | ||
| 428 | |||
| 429 | static int init_blkcipher_desc(struct blkcipher_desc *desc, const u8 *key, | ||
| 430 | unsigned int key_len, const u8 *iv, | ||
| 431 | unsigned int ivsize) | ||
| 432 | { | ||
| 433 | int ret; | ||
| 434 | |||
| 435 | desc->tfm = crypto_alloc_blkcipher(blkcipher_alg, 0, CRYPTO_ALG_ASYNC); | ||
| 436 | if (IS_ERR(desc->tfm)) { | ||
| 437 | pr_err("encrypted_key: failed to load %s transform (%ld)\n", | ||
| 438 | blkcipher_alg, PTR_ERR(desc->tfm)); | ||
| 439 | return PTR_ERR(desc->tfm); | ||
| 440 | } | ||
| 441 | desc->flags = 0; | ||
| 442 | |||
| 443 | ret = crypto_blkcipher_setkey(desc->tfm, key, key_len); | ||
| 444 | if (ret < 0) { | ||
| 445 | pr_err("encrypted_key: failed to setkey (%d)\n", ret); | ||
| 446 | crypto_free_blkcipher(desc->tfm); | ||
| 447 | return ret; | ||
| 448 | } | ||
| 449 | crypto_blkcipher_set_iv(desc->tfm, iv, ivsize); | ||
| 450 | return 0; | ||
| 451 | } | ||
| 452 | |||
| 453 | static struct key *request_master_key(struct encrypted_key_payload *epayload, | ||
| 454 | u8 **master_key, size_t *master_keylen) | ||
| 455 | { | ||
| 456 | struct key *mkey = NULL; | ||
| 457 | |||
| 458 | if (!strncmp(epayload->master_desc, KEY_TRUSTED_PREFIX, | ||
| 459 | KEY_TRUSTED_PREFIX_LEN)) { | ||
| 460 | mkey = request_trusted_key(epayload->master_desc + | ||
| 461 | KEY_TRUSTED_PREFIX_LEN, | ||
| 462 | master_key, master_keylen); | ||
| 463 | } else if (!strncmp(epayload->master_desc, KEY_USER_PREFIX, | ||
| 464 | KEY_USER_PREFIX_LEN)) { | ||
| 465 | mkey = request_user_key(epayload->master_desc + | ||
| 466 | KEY_USER_PREFIX_LEN, | ||
| 467 | master_key, master_keylen); | ||
| 468 | } else | ||
| 469 | goto out; | ||
| 470 | |||
| 471 | if (IS_ERR(mkey)) { | ||
| 472 | pr_info("encrypted_key: key %s not found", | ||
| 473 | epayload->master_desc); | ||
| 474 | goto out; | ||
| 475 | } | ||
| 476 | |||
| 477 | dump_master_key(*master_key, *master_keylen); | ||
| 478 | out: | ||
| 479 | return mkey; | ||
| 480 | } | ||
| 481 | |||
| 482 | /* Before returning data to userspace, encrypt decrypted data. */ | ||
| 483 | static int derived_key_encrypt(struct encrypted_key_payload *epayload, | ||
| 484 | const u8 *derived_key, | ||
| 485 | unsigned int derived_keylen) | ||
| 486 | { | ||
| 487 | struct scatterlist sg_in[2]; | ||
| 488 | struct scatterlist sg_out[1]; | ||
| 489 | struct blkcipher_desc desc; | ||
| 490 | unsigned int encrypted_datalen; | ||
| 491 | unsigned int padlen; | ||
| 492 | char pad[16]; | ||
| 493 | int ret; | ||
| 494 | |||
| 495 | encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); | ||
| 496 | padlen = encrypted_datalen - epayload->decrypted_datalen; | ||
| 497 | |||
| 498 | ret = init_blkcipher_desc(&desc, derived_key, derived_keylen, | ||
| 499 | epayload->iv, ivsize); | ||
| 500 | if (ret < 0) | ||
| 501 | goto out; | ||
| 502 | dump_decrypted_data(epayload); | ||
| 503 | |||
| 504 | memset(pad, 0, sizeof pad); | ||
| 505 | sg_init_table(sg_in, 2); | ||
| 506 | sg_set_buf(&sg_in[0], epayload->decrypted_data, | ||
| 507 | epayload->decrypted_datalen); | ||
| 508 | sg_set_buf(&sg_in[1], pad, padlen); | ||
| 509 | |||
| 510 | sg_init_table(sg_out, 1); | ||
| 511 | sg_set_buf(sg_out, epayload->encrypted_data, encrypted_datalen); | ||
| 512 | |||
| 513 | ret = crypto_blkcipher_encrypt(&desc, sg_out, sg_in, encrypted_datalen); | ||
| 514 | crypto_free_blkcipher(desc.tfm); | ||
| 515 | if (ret < 0) | ||
| 516 | pr_err("encrypted_key: failed to encrypt (%d)\n", ret); | ||
| 517 | else | ||
| 518 | dump_encrypted_data(epayload, encrypted_datalen); | ||
| 519 | out: | ||
| 520 | return ret; | ||
| 521 | } | ||
| 522 | |||
| 523 | static int datablob_hmac_append(struct encrypted_key_payload *epayload, | ||
| 524 | const u8 *master_key, size_t master_keylen) | ||
| 525 | { | ||
| 526 | u8 derived_key[HASH_SIZE]; | ||
| 527 | u8 *digest; | ||
| 528 | int ret; | ||
| 529 | |||
| 530 | ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen); | ||
| 531 | if (ret < 0) | ||
| 532 | goto out; | ||
| 533 | |||
| 534 | digest = epayload->format + epayload->datablob_len; | ||
| 535 | ret = calc_hmac(digest, derived_key, sizeof derived_key, | ||
| 536 | epayload->format, epayload->datablob_len); | ||
| 537 | if (!ret) | ||
| 538 | dump_hmac(NULL, digest, HASH_SIZE); | ||
| 539 | out: | ||
| 540 | return ret; | ||
| 541 | } | ||
| 542 | |||
| 543 | /* verify HMAC before decrypting encrypted key */ | ||
| 544 | static int datablob_hmac_verify(struct encrypted_key_payload *epayload, | ||
| 545 | const u8 *format, const u8 *master_key, | ||
| 546 | size_t master_keylen) | ||
| 547 | { | ||
| 548 | u8 derived_key[HASH_SIZE]; | ||
| 549 | u8 digest[HASH_SIZE]; | ||
| 550 | int ret; | ||
| 551 | char *p; | ||
| 552 | unsigned short len; | ||
| 553 | |||
| 554 | ret = get_derived_key(derived_key, AUTH_KEY, master_key, master_keylen); | ||
| 555 | if (ret < 0) | ||
| 556 | goto out; | ||
| 557 | |||
| 558 | len = epayload->datablob_len; | ||
| 559 | if (!format) { | ||
| 560 | p = epayload->master_desc; | ||
| 561 | len -= strlen(epayload->format) + 1; | ||
| 562 | } else | ||
| 563 | p = epayload->format; | ||
| 564 | |||
| 565 | ret = calc_hmac(digest, derived_key, sizeof derived_key, p, len); | ||
| 566 | if (ret < 0) | ||
| 567 | goto out; | ||
| 568 | ret = memcmp(digest, epayload->format + epayload->datablob_len, | ||
| 569 | sizeof digest); | ||
| 570 | if (ret) { | ||
| 571 | ret = -EINVAL; | ||
| 572 | dump_hmac("datablob", | ||
| 573 | epayload->format + epayload->datablob_len, | ||
| 574 | HASH_SIZE); | ||
| 575 | dump_hmac("calc", digest, HASH_SIZE); | ||
| 576 | } | ||
| 577 | out: | ||
| 578 | return ret; | ||
| 579 | } | ||
| 580 | |||
| 581 | static int derived_key_decrypt(struct encrypted_key_payload *epayload, | ||
| 582 | const u8 *derived_key, | ||
| 583 | unsigned int derived_keylen) | ||
| 584 | { | ||
| 585 | struct scatterlist sg_in[1]; | ||
| 586 | struct scatterlist sg_out[2]; | ||
| 587 | struct blkcipher_desc desc; | ||
| 588 | unsigned int encrypted_datalen; | ||
| 589 | char pad[16]; | ||
| 590 | int ret; | ||
| 591 | |||
| 592 | encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); | ||
| 593 | ret = init_blkcipher_desc(&desc, derived_key, derived_keylen, | ||
| 594 | epayload->iv, ivsize); | ||
| 595 | if (ret < 0) | ||
| 596 | goto out; | ||
| 597 | dump_encrypted_data(epayload, encrypted_datalen); | ||
| 598 | |||
| 599 | memset(pad, 0, sizeof pad); | ||
| 600 | sg_init_table(sg_in, 1); | ||
| 601 | sg_init_table(sg_out, 2); | ||
| 602 | sg_set_buf(sg_in, epayload->encrypted_data, encrypted_datalen); | ||
| 603 | sg_set_buf(&sg_out[0], epayload->decrypted_data, | ||
| 604 | epayload->decrypted_datalen); | ||
| 605 | sg_set_buf(&sg_out[1], pad, sizeof pad); | ||
| 606 | |||
| 607 | ret = crypto_blkcipher_decrypt(&desc, sg_out, sg_in, encrypted_datalen); | ||
| 608 | crypto_free_blkcipher(desc.tfm); | ||
| 609 | if (ret < 0) | ||
| 610 | goto out; | ||
| 611 | dump_decrypted_data(epayload); | ||
| 612 | out: | ||
| 613 | return ret; | ||
| 614 | } | ||
| 615 | |||
| 616 | /* Allocate memory for decrypted key and datablob. */ | ||
| 617 | static struct encrypted_key_payload *encrypted_key_alloc(struct key *key, | ||
| 618 | const char *format, | ||
| 619 | const char *master_desc, | ||
| 620 | const char *datalen) | ||
| 621 | { | ||
| 622 | struct encrypted_key_payload *epayload = NULL; | ||
| 623 | unsigned short datablob_len; | ||
| 624 | unsigned short decrypted_datalen; | ||
| 625 | unsigned short payload_datalen; | ||
| 626 | unsigned int encrypted_datalen; | ||
| 627 | unsigned int format_len; | ||
| 628 | long dlen; | ||
| 629 | int ret; | ||
| 630 | |||
| 631 | ret = strict_strtol(datalen, 10, &dlen); | ||
| 632 | if (ret < 0 || dlen < MIN_DATA_SIZE || dlen > MAX_DATA_SIZE) | ||
| 633 | return ERR_PTR(-EINVAL); | ||
| 634 | |||
| 635 | format_len = (!format) ? strlen(key_format_default) : strlen(format); | ||
| 636 | decrypted_datalen = dlen; | ||
| 637 | payload_datalen = decrypted_datalen; | ||
| 638 | if (format && !strcmp(format, key_format_ecryptfs)) { | ||
| 639 | if (dlen != ECRYPTFS_MAX_KEY_BYTES) { | ||
| 640 | pr_err("encrypted_key: keylen for the ecryptfs format " | ||
| 641 | "must be equal to %d bytes\n", | ||
| 642 | ECRYPTFS_MAX_KEY_BYTES); | ||
| 643 | return ERR_PTR(-EINVAL); | ||
| 644 | } | ||
| 645 | decrypted_datalen = ECRYPTFS_MAX_KEY_BYTES; | ||
| 646 | payload_datalen = sizeof(struct ecryptfs_auth_tok); | ||
| 647 | } | ||
| 648 | |||
| 649 | encrypted_datalen = roundup(decrypted_datalen, blksize); | ||
| 650 | |||
| 651 | datablob_len = format_len + 1 + strlen(master_desc) + 1 | ||
| 652 | + strlen(datalen) + 1 + ivsize + 1 + encrypted_datalen; | ||
| 653 | |||
| 654 | ret = key_payload_reserve(key, payload_datalen + datablob_len | ||
| 655 | + HASH_SIZE + 1); | ||
| 656 | if (ret < 0) | ||
| 657 | return ERR_PTR(ret); | ||
| 658 | |||
| 659 | epayload = kzalloc(sizeof(*epayload) + payload_datalen + | ||
| 660 | datablob_len + HASH_SIZE + 1, GFP_KERNEL); | ||
| 661 | if (!epayload) | ||
| 662 | return ERR_PTR(-ENOMEM); | ||
| 663 | |||
| 664 | epayload->payload_datalen = payload_datalen; | ||
| 665 | epayload->decrypted_datalen = decrypted_datalen; | ||
| 666 | epayload->datablob_len = datablob_len; | ||
| 667 | return epayload; | ||
| 668 | } | ||
| 669 | |||
| 670 | static int encrypted_key_decrypt(struct encrypted_key_payload *epayload, | ||
| 671 | const char *format, const char *hex_encoded_iv) | ||
| 672 | { | ||
| 673 | struct key *mkey; | ||
| 674 | u8 derived_key[HASH_SIZE]; | ||
| 675 | u8 *master_key; | ||
| 676 | u8 *hmac; | ||
| 677 | const char *hex_encoded_data; | ||
| 678 | unsigned int encrypted_datalen; | ||
| 679 | size_t master_keylen; | ||
| 680 | size_t asciilen; | ||
| 681 | int ret; | ||
| 682 | |||
| 683 | encrypted_datalen = roundup(epayload->decrypted_datalen, blksize); | ||
| 684 | asciilen = (ivsize + 1 + encrypted_datalen + HASH_SIZE) * 2; | ||
| 685 | if (strlen(hex_encoded_iv) != asciilen) | ||
| 686 | return -EINVAL; | ||
| 687 | |||
| 688 | hex_encoded_data = hex_encoded_iv + (2 * ivsize) + 2; | ||
| 689 | hex2bin(epayload->iv, hex_encoded_iv, ivsize); | ||
| 690 | hex2bin(epayload->encrypted_data, hex_encoded_data, encrypted_datalen); | ||
| 691 | |||
| 692 | hmac = epayload->format + epayload->datablob_len; | ||
| 693 | hex2bin(hmac, hex_encoded_data + (encrypted_datalen * 2), HASH_SIZE); | ||
| 694 | |||
| 695 | mkey = request_master_key(epayload, &master_key, &master_keylen); | ||
| 696 | if (IS_ERR(mkey)) | ||
| 697 | return PTR_ERR(mkey); | ||
| 698 | |||
| 699 | ret = datablob_hmac_verify(epayload, format, master_key, master_keylen); | ||
| 700 | if (ret < 0) { | ||
| 701 | pr_err("encrypted_key: bad hmac (%d)\n", ret); | ||
| 702 | goto out; | ||
| 703 | } | ||
| 704 | |||
| 705 | ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen); | ||
| 706 | if (ret < 0) | ||
| 707 | goto out; | ||
| 708 | |||
| 709 | ret = derived_key_decrypt(epayload, derived_key, sizeof derived_key); | ||
| 710 | if (ret < 0) | ||
| 711 | pr_err("encrypted_key: failed to decrypt key (%d)\n", ret); | ||
| 712 | out: | ||
| 713 | up_read(&mkey->sem); | ||
| 714 | key_put(mkey); | ||
| 715 | return ret; | ||
| 716 | } | ||
| 717 | |||
| 718 | static void __ekey_init(struct encrypted_key_payload *epayload, | ||
| 719 | const char *format, const char *master_desc, | ||
| 720 | const char *datalen) | ||
| 721 | { | ||
| 722 | unsigned int format_len; | ||
| 723 | |||
| 724 | format_len = (!format) ? strlen(key_format_default) : strlen(format); | ||
| 725 | epayload->format = epayload->payload_data + epayload->payload_datalen; | ||
| 726 | epayload->master_desc = epayload->format + format_len + 1; | ||
| 727 | epayload->datalen = epayload->master_desc + strlen(master_desc) + 1; | ||
| 728 | epayload->iv = epayload->datalen + strlen(datalen) + 1; | ||
| 729 | epayload->encrypted_data = epayload->iv + ivsize + 1; | ||
| 730 | epayload->decrypted_data = epayload->payload_data; | ||
| 731 | |||
| 732 | if (!format) | ||
| 733 | memcpy(epayload->format, key_format_default, format_len); | ||
| 734 | else { | ||
| 735 | if (!strcmp(format, key_format_ecryptfs)) | ||
| 736 | epayload->decrypted_data = | ||
| 737 | ecryptfs_get_auth_tok_key((struct ecryptfs_auth_tok *)epayload->payload_data); | ||
| 738 | |||
| 739 | memcpy(epayload->format, format, format_len); | ||
| 740 | } | ||
| 741 | |||
| 742 | memcpy(epayload->master_desc, master_desc, strlen(master_desc)); | ||
| 743 | memcpy(epayload->datalen, datalen, strlen(datalen)); | ||
| 744 | } | ||
| 745 | |||
| 746 | /* | ||
| 747 | * encrypted_init - initialize an encrypted key | ||
| 748 | * | ||
| 749 | * For a new key, use a random number for both the iv and data | ||
| 750 | * itself. For an old key, decrypt the hex encoded data. | ||
| 751 | */ | ||
| 752 | static int encrypted_init(struct encrypted_key_payload *epayload, | ||
| 753 | const char *key_desc, const char *format, | ||
| 754 | const char *master_desc, const char *datalen, | ||
| 755 | const char *hex_encoded_iv) | ||
| 756 | { | ||
| 757 | int ret = 0; | ||
| 758 | |||
| 759 | if (format && !strcmp(format, key_format_ecryptfs)) { | ||
| 760 | ret = valid_ecryptfs_desc(key_desc); | ||
| 761 | if (ret < 0) | ||
| 762 | return ret; | ||
| 763 | |||
| 764 | ecryptfs_fill_auth_tok((struct ecryptfs_auth_tok *)epayload->payload_data, | ||
| 765 | key_desc); | ||
| 766 | } | ||
| 767 | |||
| 768 | __ekey_init(epayload, format, master_desc, datalen); | ||
| 769 | if (!hex_encoded_iv) { | ||
| 770 | get_random_bytes(epayload->iv, ivsize); | ||
| 771 | |||
| 772 | get_random_bytes(epayload->decrypted_data, | ||
| 773 | epayload->decrypted_datalen); | ||
| 774 | } else | ||
| 775 | ret = encrypted_key_decrypt(epayload, format, hex_encoded_iv); | ||
| 776 | return ret; | ||
| 777 | } | ||
| 778 | |||
| 779 | /* | ||
| 780 | * encrypted_instantiate - instantiate an encrypted key | ||
| 781 | * | ||
| 782 | * Decrypt an existing encrypted datablob or create a new encrypted key | ||
| 783 | * based on a kernel random number. | ||
| 784 | * | ||
| 785 | * On success, return 0. Otherwise return errno. | ||
| 786 | */ | ||
| 787 | static int encrypted_instantiate(struct key *key, const void *data, | ||
| 788 | size_t datalen) | ||
| 789 | { | ||
| 790 | struct encrypted_key_payload *epayload = NULL; | ||
| 791 | char *datablob = NULL; | ||
| 792 | const char *format = NULL; | ||
| 793 | char *master_desc = NULL; | ||
| 794 | char *decrypted_datalen = NULL; | ||
| 795 | char *hex_encoded_iv = NULL; | ||
| 796 | int ret; | ||
| 797 | |||
| 798 | if (datalen <= 0 || datalen > 32767 || !data) | ||
| 799 | return -EINVAL; | ||
| 800 | |||
| 801 | datablob = kmalloc(datalen + 1, GFP_KERNEL); | ||
| 802 | if (!datablob) | ||
| 803 | return -ENOMEM; | ||
| 804 | datablob[datalen] = 0; | ||
| 805 | memcpy(datablob, data, datalen); | ||
| 806 | ret = datablob_parse(datablob, &format, &master_desc, | ||
| 807 | &decrypted_datalen, &hex_encoded_iv); | ||
| 808 | if (ret < 0) | ||
| 809 | goto out; | ||
| 810 | |||
| 811 | epayload = encrypted_key_alloc(key, format, master_desc, | ||
| 812 | decrypted_datalen); | ||
| 813 | if (IS_ERR(epayload)) { | ||
| 814 | ret = PTR_ERR(epayload); | ||
| 815 | goto out; | ||
| 816 | } | ||
| 817 | ret = encrypted_init(epayload, key->description, format, master_desc, | ||
| 818 | decrypted_datalen, hex_encoded_iv); | ||
| 819 | if (ret < 0) { | ||
| 820 | kfree(epayload); | ||
| 821 | goto out; | ||
| 822 | } | ||
| 823 | |||
| 824 | rcu_assign_pointer(key->payload.data, epayload); | ||
| 825 | out: | ||
| 826 | kfree(datablob); | ||
| 827 | return ret; | ||
| 828 | } | ||
| 829 | |||
| 830 | static void encrypted_rcu_free(struct rcu_head *rcu) | ||
| 831 | { | ||
| 832 | struct encrypted_key_payload *epayload; | ||
| 833 | |||
| 834 | epayload = container_of(rcu, struct encrypted_key_payload, rcu); | ||
| 835 | memset(epayload->decrypted_data, 0, epayload->decrypted_datalen); | ||
| 836 | kfree(epayload); | ||
| 837 | } | ||
| 838 | |||
| 839 | /* | ||
| 840 | * encrypted_update - update the master key description | ||
| 841 | * | ||
| 842 | * Change the master key description for an existing encrypted key. | ||
| 843 | * The next read will return an encrypted datablob using the new | ||
| 844 | * master key description. | ||
| 845 | * | ||
| 846 | * On success, return 0. Otherwise return errno. | ||
| 847 | */ | ||
| 848 | static int encrypted_update(struct key *key, const void *data, size_t datalen) | ||
| 849 | { | ||
| 850 | struct encrypted_key_payload *epayload = key->payload.data; | ||
| 851 | struct encrypted_key_payload *new_epayload; | ||
| 852 | char *buf; | ||
| 853 | char *new_master_desc = NULL; | ||
| 854 | const char *format = NULL; | ||
| 855 | int ret = 0; | ||
| 856 | |||
| 857 | if (datalen <= 0 || datalen > 32767 || !data) | ||
| 858 | return -EINVAL; | ||
| 859 | |||
| 860 | buf = kmalloc(datalen + 1, GFP_KERNEL); | ||
| 861 | if (!buf) | ||
| 862 | return -ENOMEM; | ||
| 863 | |||
| 864 | buf[datalen] = 0; | ||
| 865 | memcpy(buf, data, datalen); | ||
| 866 | ret = datablob_parse(buf, &format, &new_master_desc, NULL, NULL); | ||
| 867 | if (ret < 0) | ||
| 868 | goto out; | ||
| 869 | |||
| 870 | ret = valid_master_desc(new_master_desc, epayload->master_desc); | ||
| 871 | if (ret < 0) | ||
| 872 | goto out; | ||
| 873 | |||
| 874 | new_epayload = encrypted_key_alloc(key, epayload->format, | ||
| 875 | new_master_desc, epayload->datalen); | ||
| 876 | if (IS_ERR(new_epayload)) { | ||
| 877 | ret = PTR_ERR(new_epayload); | ||
| 878 | goto out; | ||
| 879 | } | ||
| 880 | |||
| 881 | __ekey_init(new_epayload, epayload->format, new_master_desc, | ||
| 882 | epayload->datalen); | ||
| 883 | |||
| 884 | memcpy(new_epayload->iv, epayload->iv, ivsize); | ||
| 885 | memcpy(new_epayload->payload_data, epayload->payload_data, | ||
| 886 | epayload->payload_datalen); | ||
| 887 | |||
| 888 | rcu_assign_pointer(key->payload.data, new_epayload); | ||
| 889 | call_rcu(&epayload->rcu, encrypted_rcu_free); | ||
| 890 | out: | ||
| 891 | kfree(buf); | ||
| 892 | return ret; | ||
| 893 | } | ||
| 894 | |||
| 895 | /* | ||
| 896 | * encrypted_read - format and copy the encrypted data to userspace | ||
| 897 | * | ||
| 898 | * The resulting datablob format is: | ||
| 899 | * <master-key name> <decrypted data length> <encrypted iv> <encrypted data> | ||
| 900 | * | ||
| 901 | * On success, return to userspace the encrypted key datablob size. | ||
| 902 | */ | ||
| 903 | static long encrypted_read(const struct key *key, char __user *buffer, | ||
| 904 | size_t buflen) | ||
| 905 | { | ||
| 906 | struct encrypted_key_payload *epayload; | ||
| 907 | struct key *mkey; | ||
| 908 | u8 *master_key; | ||
| 909 | size_t master_keylen; | ||
| 910 | char derived_key[HASH_SIZE]; | ||
| 911 | char *ascii_buf; | ||
| 912 | size_t asciiblob_len; | ||
| 913 | int ret; | ||
| 914 | |||
| 915 | epayload = rcu_dereference_key(key); | ||
| 916 | |||
| 917 | /* returns the hex encoded iv, encrypted-data, and hmac as ascii */ | ||
| 918 | asciiblob_len = epayload->datablob_len + ivsize + 1 | ||
| 919 | + roundup(epayload->decrypted_datalen, blksize) | ||
| 920 | + (HASH_SIZE * 2); | ||
| 921 | |||
| 922 | if (!buffer || buflen < asciiblob_len) | ||
| 923 | return asciiblob_len; | ||
| 924 | |||
| 925 | mkey = request_master_key(epayload, &master_key, &master_keylen); | ||
| 926 | if (IS_ERR(mkey)) | ||
| 927 | return PTR_ERR(mkey); | ||
| 928 | |||
| 929 | ret = get_derived_key(derived_key, ENC_KEY, master_key, master_keylen); | ||
| 930 | if (ret < 0) | ||
| 931 | goto out; | ||
| 932 | |||
| 933 | ret = derived_key_encrypt(epayload, derived_key, sizeof derived_key); | ||
| 934 | if (ret < 0) | ||
| 935 | goto out; | ||
| 936 | |||
| 937 | ret = datablob_hmac_append(epayload, master_key, master_keylen); | ||
| 938 | if (ret < 0) | ||
| 939 | goto out; | ||
| 940 | |||
| 941 | ascii_buf = datablob_format(epayload, asciiblob_len); | ||
| 942 | if (!ascii_buf) { | ||
| 943 | ret = -ENOMEM; | ||
| 944 | goto out; | ||
| 945 | } | ||
| 946 | |||
| 947 | up_read(&mkey->sem); | ||
| 948 | key_put(mkey); | ||
| 949 | |||
| 950 | if (copy_to_user(buffer, ascii_buf, asciiblob_len) != 0) | ||
| 951 | ret = -EFAULT; | ||
| 952 | kfree(ascii_buf); | ||
| 953 | |||
| 954 | return asciiblob_len; | ||
| 955 | out: | ||
| 956 | up_read(&mkey->sem); | ||
| 957 | key_put(mkey); | ||
| 958 | return ret; | ||
| 959 | } | ||
| 960 | |||
| 961 | /* | ||
| 962 | * encrypted_destroy - before freeing the key, clear the decrypted data | ||
| 963 | * | ||
| 964 | * Before freeing the key, clear the memory containing the decrypted | ||
| 965 | * key data. | ||
| 966 | */ | ||
| 967 | static void encrypted_destroy(struct key *key) | ||
| 968 | { | ||
| 969 | struct encrypted_key_payload *epayload = key->payload.data; | ||
| 970 | |||
| 971 | if (!epayload) | ||
| 972 | return; | ||
| 973 | |||
| 974 | memset(epayload->decrypted_data, 0, epayload->decrypted_datalen); | ||
| 975 | kfree(key->payload.data); | ||
| 976 | } | ||
| 977 | |||
| 978 | struct key_type key_type_encrypted = { | ||
| 979 | .name = "encrypted", | ||
| 980 | .instantiate = encrypted_instantiate, | ||
| 981 | .update = encrypted_update, | ||
| 982 | .match = user_match, | ||
| 983 | .destroy = encrypted_destroy, | ||
| 984 | .describe = user_describe, | ||
| 985 | .read = encrypted_read, | ||
| 986 | }; | ||
| 987 | EXPORT_SYMBOL_GPL(key_type_encrypted); | ||
| 988 | |||
| 989 | static void encrypted_shash_release(void) | ||
| 990 | { | ||
| 991 | if (hashalg) | ||
| 992 | crypto_free_shash(hashalg); | ||
| 993 | if (hmacalg) | ||
| 994 | crypto_free_shash(hmacalg); | ||
| 995 | } | ||
| 996 | |||
| 997 | static int __init encrypted_shash_alloc(void) | ||
| 998 | { | ||
| 999 | int ret; | ||
| 1000 | |||
| 1001 | hmacalg = crypto_alloc_shash(hmac_alg, 0, CRYPTO_ALG_ASYNC); | ||
| 1002 | if (IS_ERR(hmacalg)) { | ||
| 1003 | pr_info("encrypted_key: could not allocate crypto %s\n", | ||
| 1004 | hmac_alg); | ||
| 1005 | return PTR_ERR(hmacalg); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | hashalg = crypto_alloc_shash(hash_alg, 0, CRYPTO_ALG_ASYNC); | ||
| 1009 | if (IS_ERR(hashalg)) { | ||
| 1010 | pr_info("encrypted_key: could not allocate crypto %s\n", | ||
| 1011 | hash_alg); | ||
| 1012 | ret = PTR_ERR(hashalg); | ||
| 1013 | goto hashalg_fail; | ||
| 1014 | } | ||
| 1015 | |||
| 1016 | return 0; | ||
| 1017 | |||
| 1018 | hashalg_fail: | ||
| 1019 | crypto_free_shash(hmacalg); | ||
| 1020 | return ret; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | static int __init init_encrypted(void) | ||
| 1024 | { | ||
| 1025 | int ret; | ||
| 1026 | |||
| 1027 | ret = encrypted_shash_alloc(); | ||
| 1028 | if (ret < 0) | ||
| 1029 | return ret; | ||
| 1030 | ret = register_key_type(&key_type_encrypted); | ||
| 1031 | if (ret < 0) | ||
| 1032 | goto out; | ||
| 1033 | return aes_get_sizes(); | ||
| 1034 | out: | ||
| 1035 | encrypted_shash_release(); | ||
| 1036 | return ret; | ||
| 1037 | |||
| 1038 | } | ||
| 1039 | |||
| 1040 | static void __exit cleanup_encrypted(void) | ||
| 1041 | { | ||
| 1042 | encrypted_shash_release(); | ||
| 1043 | unregister_key_type(&key_type_encrypted); | ||
| 1044 | } | ||
| 1045 | |||
| 1046 | late_initcall(init_encrypted); | ||
| 1047 | module_exit(cleanup_encrypted); | ||
| 1048 | |||
| 1049 | MODULE_LICENSE("GPL"); | ||
diff --git a/security/keys/encrypted.h b/security/keys/encrypted.h new file mode 100644 index 00000000000..cef5e2f2b7d --- /dev/null +++ b/security/keys/encrypted.h | |||
| @@ -0,0 +1,54 @@ | |||
| 1 | #ifndef __ENCRYPTED_KEY_H | ||
| 2 | #define __ENCRYPTED_KEY_H | ||
| 3 | |||
| 4 | #define ENCRYPTED_DEBUG 0 | ||
| 5 | |||
| 6 | #if ENCRYPTED_DEBUG | ||
| 7 | static inline void dump_master_key(const u8 *master_key, size_t master_keylen) | ||
| 8 | { | ||
| 9 | print_hex_dump(KERN_ERR, "master key: ", DUMP_PREFIX_NONE, 32, 1, | ||
| 10 | master_key, master_keylen, 0); | ||
| 11 | } | ||
| 12 | |||
| 13 | static inline void dump_decrypted_data(struct encrypted_key_payload *epayload) | ||
| 14 | { | ||
| 15 | print_hex_dump(KERN_ERR, "decrypted data: ", DUMP_PREFIX_NONE, 32, 1, | ||
| 16 | epayload->decrypted_data, | ||
| 17 | epayload->decrypted_datalen, 0); | ||
| 18 | } | ||
| 19 | |||
| 20 | static inline void dump_encrypted_data(struct encrypted_key_payload *epayload, | ||
| 21 | unsigned int encrypted_datalen) | ||
| 22 | { | ||
| 23 | print_hex_dump(KERN_ERR, "encrypted data: ", DUMP_PREFIX_NONE, 32, 1, | ||
| 24 | epayload->encrypted_data, encrypted_datalen, 0); | ||
| 25 | } | ||
| 26 | |||
| 27 | static inline void dump_hmac(const char *str, const u8 *digest, | ||
| 28 | unsigned int hmac_size) | ||
| 29 | { | ||
| 30 | if (str) | ||
| 31 | pr_info("encrypted_key: %s", str); | ||
| 32 | print_hex_dump(KERN_ERR, "hmac: ", DUMP_PREFIX_NONE, 32, 1, digest, | ||
| 33 | hmac_size, 0); | ||
| 34 | } | ||
| 35 | #else | ||
| 36 | static inline void dump_master_key(const u8 *master_key, size_t master_keylen) | ||
| 37 | { | ||
| 38 | } | ||
| 39 | |||
| 40 | static inline void dump_decrypted_data(struct encrypted_key_payload *epayload) | ||
| 41 | { | ||
| 42 | } | ||
| 43 | |||
| 44 | static inline void dump_encrypted_data(struct encrypted_key_payload *epayload, | ||
| 45 | unsigned int encrypted_datalen) | ||
| 46 | { | ||
| 47 | } | ||
| 48 | |||
| 49 | static inline void dump_hmac(const char *str, const u8 *digest, | ||
| 50 | unsigned int hmac_size) | ||
| 51 | { | ||
| 52 | } | ||
| 53 | #endif | ||
| 54 | #endif | ||
diff --git a/security/tf_driver/Kconfig b/security/tf_driver/Kconfig new file mode 100644 index 00000000000..2a980c5ade4 --- /dev/null +++ b/security/tf_driver/Kconfig | |||
| @@ -0,0 +1,8 @@ | |||
| 1 | config TRUSTED_FOUNDATIONS | ||
| 2 | bool "Enable TF Driver" | ||
| 3 | default n | ||
| 4 | select CRYPTO_SHA1 | ||
| 5 | help | ||
| 6 | This option adds kernel support for communication with the Trusted Foundations. | ||
| 7 | If you are unsure how to answer this question, answer N. | ||
| 8 | |||
diff --git a/security/tf_driver/Makefile b/security/tf_driver/Makefile new file mode 100644 index 00000000000..dfadb7d9740 --- /dev/null +++ b/security/tf_driver/Makefile | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | # | ||
| 2 | # Copyright (c) 2006-2010 Trusted Logic S.A. | ||
| 3 | # All Rights Reserved. | ||
| 4 | # | ||
| 5 | # This program is free software; you can redistribute it and/or | ||
| 6 | # modify it under the terms of the GNU General Public License as | ||
| 7 | # published by the Free Software Foundation; either version 2 of | ||
| 8 | # the License, or (at your option) any later version. | ||
| 9 | # | ||
| 10 | # This program is distributed in the hope that it will be useful, | ||
| 11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | # GNU General Public License for more details. | ||
| 14 | # | ||
| 15 | # You should have received a copy of the GNU General Public License | ||
| 16 | # along with this program; if not, write to the Free Software | ||
| 17 | # Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 18 | # MA 02111-1307 USA | ||
| 19 | # | ||
| 20 | |||
| 21 | # debug options | ||
| 22 | #EXTRA_CFLAGS += -O0 -DDEBUG -D_DEBUG -DCONFIG_TF_DRIVER_DEBUG_SUPPORT | ||
| 23 | EXTRA_CFLAGS += -DNDEBUG | ||
| 24 | EXTRA_CFLAGS += -DLINUX -DCONFIG_TF_TRUSTZONE -DCONFIG_TFN | ||
| 25 | |||
| 26 | ifdef S_VERSION_BUILD | ||
| 27 | EXTRA_CFLAGS += -DS_VERSION_BUILD=$(S_VERSION_BUILD) | ||
| 28 | endif | ||
| 29 | |||
| 30 | tf_driver-objs += tf_util.o | ||
| 31 | tf_driver-objs += tf_conn.o | ||
| 32 | tf_driver-objs += tf_device.o | ||
| 33 | tf_driver-objs += tf_comm.o | ||
| 34 | tf_driver-objs += tf_comm_tz.o | ||
| 35 | |||
| 36 | obj-$(CONFIG_TRUSTED_FOUNDATIONS) += tf_driver.o | ||
diff --git a/security/tf_driver/s_version.h b/security/tf_driver/s_version.h new file mode 100644 index 00000000000..6244d3fe7e8 --- /dev/null +++ b/security/tf_driver/s_version.h | |||
| @@ -0,0 +1,92 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 17 | * MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef __S_VERSION_H__ | ||
| 21 | #define __S_VERSION_H__ | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Usage: define S_VERSION_BUILD on the compiler's command line. | ||
| 25 | * | ||
| 26 | * Then set: | ||
| 27 | * - S_VERSION_OS | ||
| 28 | * - S_VERSION_PLATFORM | ||
| 29 | * - S_VERSION_MAIN | ||
| 30 | * - S_VERSION_ENG is optional | ||
| 31 | * - S_VERSION_PATCH is optional | ||
| 32 | * - S_VERSION_BUILD = 0 if S_VERSION_BUILD not defined or empty | ||
| 33 | */ | ||
| 34 | |||
| 35 | #define S_VERSION_OS "A" /* "A" for all Android */ | ||
| 36 | #define S_VERSION_PLATFORM "B" /* "B" for Tegra3 */ | ||
| 37 | |||
| 38 | /* | ||
| 39 | * This version number must be updated for each new release | ||
| 40 | */ | ||
| 41 | #define S_VERSION_MAIN "01.03" | ||
| 42 | |||
| 43 | /* | ||
| 44 | * If this is a patch or engineering version use the following | ||
| 45 | * defines to set the version number. Else set these values to 0. | ||
| 46 | */ | ||
| 47 | #define S_VERSION_ENG 0 | ||
| 48 | #define S_VERSION_PATCH 0 | ||
| 49 | |||
| 50 | #ifdef S_VERSION_BUILD | ||
| 51 | /* TRICK: detect if S_VERSION is defined but empty */ | ||
| 52 | #if 0 == S_VERSION_BUILD-0 | ||
| 53 | #undef S_VERSION_BUILD | ||
| 54 | #define S_VERSION_BUILD 0 | ||
| 55 | #endif | ||
| 56 | #else | ||
| 57 | /* S_VERSION_BUILD is not defined */ | ||
| 58 | #define S_VERSION_BUILD 0 | ||
| 59 | #endif | ||
| 60 | |||
| 61 | #define __STRINGIFY(X) #X | ||
| 62 | #define __STRINGIFY2(X) __STRINGIFY(X) | ||
| 63 | |||
| 64 | #if S_VERSION_ENG != 0 | ||
| 65 | #define _S_VERSION_ENG "e" __STRINGIFY2(S_VERSION_ENG) | ||
| 66 | #else | ||
| 67 | #define _S_VERSION_ENG "" | ||
| 68 | #endif | ||
| 69 | |||
| 70 | #if S_VERSION_PATCH != 0 | ||
| 71 | #define _S_VERSION_PATCH "p" __STRINGIFY2(S_VERSION_PATCH) | ||
| 72 | #else | ||
| 73 | #define _S_VERSION_PATCH "" | ||
| 74 | #endif | ||
| 75 | |||
| 76 | #if !defined(NDEBUG) || defined(_DEBUG) | ||
| 77 | #define S_VERSION_VARIANT "D " | ||
| 78 | #else | ||
| 79 | #define S_VERSION_VARIANT " " | ||
| 80 | #endif | ||
| 81 | |||
| 82 | #define S_VERSION_STRING \ | ||
| 83 | "TFN" \ | ||
| 84 | S_VERSION_OS \ | ||
| 85 | S_VERSION_PLATFORM \ | ||
| 86 | S_VERSION_MAIN \ | ||
| 87 | _S_VERSION_ENG \ | ||
| 88 | _S_VERSION_PATCH \ | ||
| 89 | "." __STRINGIFY2(S_VERSION_BUILD) " " \ | ||
| 90 | S_VERSION_VARIANT | ||
| 91 | |||
| 92 | #endif /* __S_VERSION_H__ */ | ||
diff --git a/security/tf_driver/tf_comm.c b/security/tf_driver/tf_comm.c new file mode 100644 index 00000000000..16915beb406 --- /dev/null +++ b/security/tf_driver/tf_comm.c | |||
| @@ -0,0 +1,1745 @@ | |||
| 1 | /** | ||
| 2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 17 | * MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <asm/div64.h> | ||
| 21 | #include <asm/system.h> | ||
| 22 | #include <linux/version.h> | ||
| 23 | #include <asm/cputype.h> | ||
| 24 | #include <linux/interrupt.h> | ||
| 25 | #include <linux/page-flags.h> | ||
| 26 | #include <linux/pagemap.h> | ||
| 27 | #include <linux/vmalloc.h> | ||
| 28 | #include <linux/jiffies.h> | ||
| 29 | #include <linux/freezer.h> | ||
| 30 | |||
| 31 | #include "tf_defs.h" | ||
| 32 | #include "tf_comm.h" | ||
| 33 | #include "tf_protocol.h" | ||
| 34 | #include "tf_util.h" | ||
| 35 | #include "tf_conn.h" | ||
| 36 | |||
| 37 | #ifdef CONFIG_TF_ZEBRA | ||
| 38 | #include "tf_zebra.h" | ||
| 39 | #endif | ||
| 40 | |||
| 41 | /*--------------------------------------------------------------------------- | ||
| 42 | * Internal Constants | ||
| 43 | *---------------------------------------------------------------------------*/ | ||
| 44 | |||
| 45 | /* | ||
| 46 | * shared memories descriptor constants | ||
| 47 | */ | ||
| 48 | #define DESCRIPTOR_B_MASK (1 << 2) | ||
| 49 | #define DESCRIPTOR_C_MASK (1 << 3) | ||
| 50 | #define DESCRIPTOR_S_MASK (1 << 10) | ||
| 51 | |||
| 52 | #define L1_COARSE_DESCRIPTOR_BASE (0x00000001) | ||
| 53 | #define L1_COARSE_DESCRIPTOR_ADDR_MASK (0xFFFFFC00) | ||
| 54 | #define L1_COARSE_DESCRIPTOR_V13_12_SHIFT (5) | ||
| 55 | |||
| 56 | #define L2_PAGE_DESCRIPTOR_BASE (0x00000003) | ||
| 57 | #define L2_PAGE_DESCRIPTOR_AP_APX_READ (0x220) | ||
| 58 | #define L2_PAGE_DESCRIPTOR_AP_APX_READ_WRITE (0x30) | ||
| 59 | |||
| 60 | #define L2_INIT_DESCRIPTOR_BASE (0x00000003) | ||
| 61 | #define L2_INIT_DESCRIPTOR_V13_12_SHIFT (4) | ||
| 62 | |||
| 63 | /* | ||
| 64 | * Reject an attempt to share a strongly-Ordered or Device memory | ||
| 65 | * Strongly-Ordered: TEX=0b000, C=0, B=0 | ||
| 66 | * Shared Device: TEX=0b000, C=0, B=1 | ||
| 67 | * Non-Shared Device: TEX=0b010, C=0, B=0 | ||
| 68 | */ | ||
| 69 | #define L2_TEX_C_B_MASK \ | ||
| 70 | ((1<<8) | (1<<7) | (1<<6) | (1<<3) | (1<<2)) | ||
| 71 | #define L2_TEX_C_B_STRONGLY_ORDERED \ | ||
| 72 | ((0<<8) | (0<<7) | (0<<6) | (0<<3) | (0<<2)) | ||
| 73 | #define L2_TEX_C_B_SHARED_DEVICE \ | ||
| 74 | ((0<<8) | (0<<7) | (0<<6) | (0<<3) | (1<<2)) | ||
| 75 | #define L2_TEX_C_B_NON_SHARED_DEVICE \ | ||
| 76 | ((0<<8) | (1<<7) | (0<<6) | (0<<3) | (0<<2)) | ||
| 77 | |||
| 78 | #define CACHE_S(x) ((x) & (1 << 24)) | ||
| 79 | #define CACHE_DSIZE(x) (((x) >> 12) & 4095) | ||
| 80 | |||
| 81 | #define TIME_IMMEDIATE ((u64) 0x0000000000000000ULL) | ||
| 82 | #define TIME_INFINITE ((u64) 0xFFFFFFFFFFFFFFFFULL) | ||
| 83 | |||
| 84 | /*--------------------------------------------------------------------------- | ||
| 85 | * atomic operation definitions | ||
| 86 | *---------------------------------------------------------------------------*/ | ||
| 87 | |||
| 88 | /* | ||
| 89 | * Atomically updates the sync_serial_n and time_n register | ||
| 90 | * sync_serial_n and time_n modifications are thread safe | ||
| 91 | */ | ||
| 92 | void tf_set_current_time(struct tf_comm *comm) | ||
| 93 | { | ||
| 94 | u32 new_sync_serial; | ||
| 95 | struct timeval now; | ||
| 96 | u64 time64; | ||
| 97 | |||
| 98 | /* | ||
| 99 | * lock the structure while updating the L1 shared memory fields | ||
| 100 | */ | ||
| 101 | spin_lock(&comm->lock); | ||
| 102 | |||
| 103 | /* read sync_serial_n and change the TimeSlot bit field */ | ||
| 104 | new_sync_serial = | ||
| 105 | tf_read_reg32(&comm->l1_buffer->sync_serial_n) + 1; | ||
| 106 | |||
| 107 | do_gettimeofday(&now); | ||
| 108 | time64 = now.tv_sec; | ||
| 109 | time64 = (time64 * 1000) + (now.tv_usec / 1000); | ||
| 110 | |||
| 111 | /* Write the new time64 and nSyncSerial into shared memory */ | ||
| 112 | tf_write_reg64(&comm->l1_buffer->time_n[new_sync_serial & | ||
| 113 | TF_SYNC_SERIAL_TIMESLOT_N], time64); | ||
| 114 | tf_write_reg32(&comm->l1_buffer->sync_serial_n, | ||
| 115 | new_sync_serial); | ||
| 116 | |||
| 117 | spin_unlock(&comm->lock); | ||
| 118 | } | ||
| 119 | |||
| 120 | /* | ||
| 121 | * Performs the specific read timeout operation | ||
| 122 | * The difficulty here is to read atomically 2 u32 | ||
| 123 | * values from the L1 shared buffer. | ||
| 124 | * This is guaranteed by reading before and after the operation | ||
| 125 | * the timeslot given by the Secure World | ||
| 126 | */ | ||
| 127 | static inline void tf_read_timeout(struct tf_comm *comm, u64 *time) | ||
| 128 | { | ||
| 129 | u32 sync_serial_s_initial = 0; | ||
| 130 | u32 sync_serial_s_final = 1; | ||
| 131 | u64 time64; | ||
| 132 | |||
| 133 | spin_lock(&comm->lock); | ||
| 134 | |||
| 135 | while (sync_serial_s_initial != sync_serial_s_final) { | ||
| 136 | sync_serial_s_initial = tf_read_reg32( | ||
| 137 | &comm->l1_buffer->sync_serial_s); | ||
| 138 | time64 = tf_read_reg64( | ||
| 139 | &comm->l1_buffer->timeout_s[sync_serial_s_initial&1]); | ||
| 140 | |||
| 141 | sync_serial_s_final = tf_read_reg32( | ||
| 142 | &comm->l1_buffer->sync_serial_s); | ||
| 143 | } | ||
| 144 | |||
| 145 | spin_unlock(&comm->lock); | ||
| 146 | |||
| 147 | *time = time64; | ||
| 148 | } | ||
| 149 | |||
| 150 | /*---------------------------------------------------------------------------- | ||
| 151 | * SIGKILL signal handling | ||
| 152 | *----------------------------------------------------------------------------*/ | ||
| 153 | |||
| 154 | static bool sigkill_pending(void) | ||
| 155 | { | ||
| 156 | if (signal_pending(current)) { | ||
| 157 | dprintk(KERN_INFO "A signal is pending\n"); | ||
| 158 | if (sigismember(¤t->pending.signal, SIGKILL)) { | ||
| 159 | dprintk(KERN_INFO "A SIGKILL is pending\n"); | ||
| 160 | return true; | ||
| 161 | } else if (sigismember( | ||
| 162 | ¤t->signal->shared_pending.signal, SIGKILL)) { | ||
| 163 | dprintk(KERN_INFO "A SIGKILL is pending (shared)\n"); | ||
| 164 | return true; | ||
| 165 | } | ||
| 166 | } | ||
| 167 | return false; | ||
| 168 | } | ||
| 169 | |||
| 170 | /*---------------------------------------------------------------------------- | ||
| 171 | * Shared memory related operations | ||
| 172 | *----------------------------------------------------------------------------*/ | ||
| 173 | |||
| 174 | struct tf_coarse_page_table *tf_alloc_coarse_page_table( | ||
| 175 | struct tf_coarse_page_table_allocation_context *alloc_context, | ||
| 176 | u32 type) | ||
| 177 | { | ||
| 178 | struct tf_coarse_page_table *coarse_pg_table = NULL; | ||
| 179 | |||
| 180 | spin_lock(&(alloc_context->lock)); | ||
| 181 | |||
| 182 | if (!(list_empty(&(alloc_context->free_coarse_page_tables)))) { | ||
| 183 | /* | ||
| 184 | * The free list can provide us a coarse page table | ||
| 185 | * descriptor | ||
| 186 | */ | ||
| 187 | coarse_pg_table = list_first_entry( | ||
| 188 | &alloc_context->free_coarse_page_tables, | ||
| 189 | struct tf_coarse_page_table, list); | ||
| 190 | list_del(&(coarse_pg_table->list)); | ||
| 191 | |||
| 192 | coarse_pg_table->parent->ref_count++; | ||
| 193 | } else { | ||
| 194 | /* no array of coarse page tables, create a new one */ | ||
| 195 | struct tf_coarse_page_table_array *array; | ||
| 196 | void *page; | ||
| 197 | int i; | ||
| 198 | |||
| 199 | spin_unlock(&(alloc_context->lock)); | ||
| 200 | |||
| 201 | /* first allocate a new page descriptor */ | ||
| 202 | array = internal_kmalloc(sizeof(*array), GFP_KERNEL); | ||
| 203 | if (array == NULL) { | ||
| 204 | dprintk(KERN_ERR "tf_alloc_coarse_page_table(%p):" | ||
| 205 | " failed to allocate a table array\n", | ||
| 206 | alloc_context); | ||
| 207 | return NULL; | ||
| 208 | } | ||
| 209 | |||
| 210 | array->type = type; | ||
| 211 | INIT_LIST_HEAD(&(array->list)); | ||
| 212 | |||
| 213 | /* now allocate the actual page the page descriptor describes */ | ||
| 214 | page = (void *) internal_get_zeroed_page(GFP_KERNEL); | ||
| 215 | if (page == NULL) { | ||
| 216 | dprintk(KERN_ERR "tf_alloc_coarse_page_table(%p):" | ||
| 217 | " failed allocate a page\n", | ||
| 218 | alloc_context); | ||
| 219 | internal_kfree(array); | ||
| 220 | return NULL; | ||
| 221 | } | ||
| 222 | |||
| 223 | spin_lock(&(alloc_context->lock)); | ||
| 224 | |||
| 225 | /* initialize the coarse page table descriptors */ | ||
| 226 | for (i = 0; i < 4; i++) { | ||
| 227 | INIT_LIST_HEAD(&(array->coarse_page_tables[i].list)); | ||
| 228 | array->coarse_page_tables[i].descriptors = | ||
| 229 | page + (i * SIZE_1KB); | ||
| 230 | array->coarse_page_tables[i].parent = array; | ||
| 231 | |||
| 232 | if (i == 0) { | ||
| 233 | /* | ||
| 234 | * the first element is kept for the current | ||
| 235 | * coarse page table allocation | ||
| 236 | */ | ||
| 237 | coarse_pg_table = | ||
| 238 | &(array->coarse_page_tables[i]); | ||
| 239 | array->ref_count = 1; | ||
| 240 | } else { | ||
| 241 | /* | ||
| 242 | * The other elements are added to the free list | ||
| 243 | */ | ||
| 244 | list_add(&(array->coarse_page_tables[i].list), | ||
| 245 | &(alloc_context-> | ||
| 246 | free_coarse_page_tables)); | ||
| 247 | } | ||
| 248 | } | ||
| 249 | |||
| 250 | list_add(&(array->list), | ||
| 251 | &(alloc_context->coarse_page_table_arrays)); | ||
| 252 | } | ||
| 253 | spin_unlock(&(alloc_context->lock)); | ||
| 254 | |||
| 255 | return coarse_pg_table; | ||
| 256 | } | ||
| 257 | |||
| 258 | |||
| 259 | void tf_free_coarse_page_table( | ||
| 260 | struct tf_coarse_page_table_allocation_context *alloc_context, | ||
| 261 | struct tf_coarse_page_table *coarse_pg_table, | ||
| 262 | int force) | ||
| 263 | { | ||
| 264 | struct tf_coarse_page_table_array *array; | ||
| 265 | |||
| 266 | spin_lock(&(alloc_context->lock)); | ||
| 267 | |||
| 268 | array = coarse_pg_table->parent; | ||
| 269 | |||
| 270 | (array->ref_count)--; | ||
| 271 | |||
| 272 | if (array->ref_count == 0) { | ||
| 273 | /* | ||
| 274 | * no coarse page table descriptor is used | ||
| 275 | * check if we should free the whole page | ||
| 276 | */ | ||
| 277 | |||
| 278 | if ((array->type == TF_PAGE_DESCRIPTOR_TYPE_PREALLOCATED) | ||
| 279 | && (force == 0)) | ||
| 280 | /* | ||
| 281 | * This is a preallocated page, | ||
| 282 | * add the page back to the free list | ||
| 283 | */ | ||
| 284 | list_add(&(coarse_pg_table->list), | ||
| 285 | &(alloc_context->free_coarse_page_tables)); | ||
| 286 | else { | ||
| 287 | /* | ||
| 288 | * None of the page's coarse page table descriptors | ||
| 289 | * are in use, free the whole page | ||
| 290 | */ | ||
| 291 | int i; | ||
| 292 | u32 *descriptors; | ||
| 293 | |||
| 294 | /* | ||
| 295 | * remove the page's associated coarse page table | ||
| 296 | * descriptors from the free list | ||
| 297 | */ | ||
| 298 | for (i = 0; i < 4; i++) | ||
| 299 | if (&(array->coarse_page_tables[i]) != | ||
| 300 | coarse_pg_table) | ||
| 301 | list_del(&(array-> | ||
| 302 | coarse_page_tables[i].list)); | ||
| 303 | |||
| 304 | descriptors = | ||
| 305 | array->coarse_page_tables[0].descriptors; | ||
| 306 | array->coarse_page_tables[0].descriptors = NULL; | ||
| 307 | |||
| 308 | /* remove the coarse page table from the array */ | ||
| 309 | list_del(&(array->list)); | ||
| 310 | |||
| 311 | spin_unlock(&(alloc_context->lock)); | ||
| 312 | /* | ||
| 313 | * Free the page. | ||
| 314 | * The address of the page is contained in the first | ||
| 315 | * element | ||
| 316 | */ | ||
| 317 | internal_free_page((unsigned long) descriptors); | ||
| 318 | /* finaly free the array */ | ||
| 319 | internal_kfree(array); | ||
| 320 | |||
| 321 | spin_lock(&(alloc_context->lock)); | ||
| 322 | } | ||
| 323 | } else { | ||
| 324 | /* | ||
| 325 | * Some coarse page table descriptors are in use. | ||
| 326 | * Add the descriptor to the free list | ||
| 327 | */ | ||
| 328 | list_add(&(coarse_pg_table->list), | ||
| 329 | &(alloc_context->free_coarse_page_tables)); | ||
| 330 | } | ||
| 331 | |||
| 332 | spin_unlock(&(alloc_context->lock)); | ||
| 333 | } | ||
| 334 | |||
| 335 | |||
| 336 | void tf_init_coarse_page_table_allocator( | ||
| 337 | struct tf_coarse_page_table_allocation_context *alloc_context) | ||
| 338 | { | ||
| 339 | spin_lock_init(&(alloc_context->lock)); | ||
| 340 | INIT_LIST_HEAD(&(alloc_context->coarse_page_table_arrays)); | ||
| 341 | INIT_LIST_HEAD(&(alloc_context->free_coarse_page_tables)); | ||
| 342 | } | ||
| 343 | |||
| 344 | void tf_release_coarse_page_table_allocator( | ||
| 345 | struct tf_coarse_page_table_allocation_context *alloc_context) | ||
| 346 | { | ||
| 347 | spin_lock(&(alloc_context->lock)); | ||
| 348 | |||
| 349 | /* now clean up the list of page descriptors */ | ||
| 350 | while (!list_empty(&(alloc_context->coarse_page_table_arrays))) { | ||
| 351 | struct tf_coarse_page_table_array *page_desc; | ||
| 352 | u32 *descriptors; | ||
| 353 | |||
| 354 | page_desc = list_first_entry( | ||
| 355 | &alloc_context->coarse_page_table_arrays, | ||
| 356 | struct tf_coarse_page_table_array, list); | ||
| 357 | |||
| 358 | descriptors = page_desc->coarse_page_tables[0].descriptors; | ||
| 359 | list_del(&(page_desc->list)); | ||
| 360 | |||
| 361 | spin_unlock(&(alloc_context->lock)); | ||
| 362 | |||
| 363 | if (descriptors != NULL) | ||
| 364 | internal_free_page((unsigned long)descriptors); | ||
| 365 | |||
| 366 | internal_kfree(page_desc); | ||
| 367 | |||
| 368 | spin_lock(&(alloc_context->lock)); | ||
| 369 | } | ||
| 370 | |||
| 371 | spin_unlock(&(alloc_context->lock)); | ||
| 372 | } | ||
| 373 | |||
| 374 | /* | ||
| 375 | * Returns the L1 coarse page descriptor for | ||
| 376 | * a coarse page table located at address coarse_pg_table_descriptors | ||
| 377 | */ | ||
| 378 | u32 tf_get_l1_coarse_descriptor( | ||
| 379 | u32 coarse_pg_table_descriptors[256]) | ||
| 380 | { | ||
| 381 | u32 descriptor = L1_COARSE_DESCRIPTOR_BASE; | ||
| 382 | unsigned int info = read_cpuid(CPUID_CACHETYPE); | ||
| 383 | |||
| 384 | descriptor |= (virt_to_phys((void *) coarse_pg_table_descriptors) | ||
| 385 | & L1_COARSE_DESCRIPTOR_ADDR_MASK); | ||
| 386 | |||
| 387 | if (CACHE_S(info) && (CACHE_DSIZE(info) & (1 << 11))) { | ||
| 388 | dprintk(KERN_DEBUG "tf_get_l1_coarse_descriptor " | ||
| 389 | "V31-12 added to descriptor\n"); | ||
| 390 | /* the 16k alignment restriction applies */ | ||
| 391 | descriptor |= (DESCRIPTOR_V13_12_GET( | ||
| 392 | (u32)coarse_pg_table_descriptors) << | ||
| 393 | L1_COARSE_DESCRIPTOR_V13_12_SHIFT); | ||
| 394 | } | ||
| 395 | |||
| 396 | return descriptor; | ||
| 397 | } | ||
| 398 | |||
| 399 | |||
| 400 | #define dprintk_desc(...) | ||
| 401 | /* | ||
| 402 | * Returns the L2 descriptor for the specified user page. | ||
| 403 | */ | ||
| 404 | u32 tf_get_l2_descriptor_common(u32 vaddr, struct mm_struct *mm) | ||
| 405 | { | ||
| 406 | pgd_t *pgd; | ||
| 407 | pud_t *pud; | ||
| 408 | pmd_t *pmd; | ||
| 409 | pte_t *ptep; | ||
| 410 | u32 *hwpte; | ||
| 411 | u32 tex = 0; | ||
| 412 | u32 descriptor = 0; | ||
| 413 | |||
| 414 | dprintk_desc(KERN_INFO "VirtAddr = %x\n", vaddr); | ||
| 415 | pgd = pgd_offset(mm, vaddr); | ||
| 416 | dprintk_desc(KERN_INFO "pgd = %x, value=%x\n", (unsigned int) pgd, | ||
| 417 | (unsigned int) *pgd); | ||
| 418 | if (pgd_none(*pgd)) | ||
| 419 | goto error; | ||
| 420 | pud = pud_offset(pgd, vaddr); | ||
| 421 | dprintk_desc(KERN_INFO "pud = %x, value=%x\n", (unsigned int) pud, | ||
| 422 | (unsigned int) *pud); | ||
| 423 | if (pud_none(*pud)) | ||
| 424 | goto error; | ||
| 425 | pmd = pmd_offset(pud, vaddr); | ||
| 426 | dprintk_desc(KERN_INFO "pmd = %x, value=%x\n", (unsigned int) pmd, | ||
| 427 | (unsigned int) *pmd); | ||
| 428 | if (pmd_none(*pmd)) | ||
| 429 | goto error; | ||
| 430 | |||
| 431 | if (PMD_TYPE_SECT&(*pmd)) { | ||
| 432 | /* We have a section */ | ||
| 433 | dprintk_desc(KERN_INFO "Section descr=%x\n", | ||
| 434 | (unsigned int)*pmd); | ||
| 435 | if ((*pmd) & PMD_SECT_BUFFERABLE) | ||
| 436 | descriptor |= DESCRIPTOR_B_MASK; | ||
| 437 | if ((*pmd) & PMD_SECT_CACHEABLE) | ||
| 438 | descriptor |= DESCRIPTOR_C_MASK; | ||
| 439 | if ((*pmd) & PMD_SECT_S) | ||
| 440 | descriptor |= DESCRIPTOR_S_MASK; | ||
| 441 | tex = ((*pmd) >> 12) & 7; | ||
| 442 | } else { | ||
| 443 | /* We have a table */ | ||
| 444 | ptep = pte_offset_map(pmd, vaddr); | ||
| 445 | if (pte_present(*ptep)) { | ||
| 446 | dprintk_desc(KERN_INFO "L2 descr=%x\n", | ||
| 447 | (unsigned int) *ptep); | ||
| 448 | if ((*ptep) & L_PTE_MT_BUFFERABLE) | ||
| 449 | descriptor |= DESCRIPTOR_B_MASK; | ||
| 450 | if ((*ptep) & L_PTE_MT_WRITETHROUGH) | ||
| 451 | descriptor |= DESCRIPTOR_C_MASK; | ||
| 452 | if ((*ptep) & L_PTE_MT_DEV_SHARED) | ||
| 453 | descriptor |= DESCRIPTOR_S_MASK; | ||
| 454 | |||
| 455 | /* | ||
| 456 | * Linux's pte doesn't keep track of TEX value. | ||
| 457 | * Have to jump to hwpte see include/asm/pgtable.h | ||
| 458 | * (-2k before 2.6.38, then +2k) | ||
| 459 | */ | ||
| 460 | #ifdef PTE_HWTABLE_SIZE | ||
| 461 | hwpte = (u32 *) (ptep+PTE_HWTABLE_PTRS); | ||
| 462 | #else | ||
| 463 | hwpte = (u32 *) (ptep-PTRS_PER_PTE); | ||
| 464 | #endif | ||
| 465 | if (((*hwpte) & L2_DESCRIPTOR_ADDR_MASK) != | ||
| 466 | ((*ptep) & L2_DESCRIPTOR_ADDR_MASK)) | ||
| 467 | goto error; | ||
| 468 | dprintk_desc(KERN_INFO "hw descr=%x\n", *hwpte); | ||
| 469 | tex = ((*hwpte) >> 6) & 7; | ||
| 470 | pte_unmap(ptep); | ||
| 471 | } else { | ||
| 472 | pte_unmap(ptep); | ||
| 473 | goto error; | ||
| 474 | } | ||
| 475 | } | ||
| 476 | |||
| 477 | descriptor |= (tex << 6); | ||
| 478 | |||
| 479 | return descriptor; | ||
| 480 | |||
| 481 | error: | ||
| 482 | dprintk(KERN_ERR "Error occured in %s\n", __func__); | ||
| 483 | return 0; | ||
| 484 | } | ||
| 485 | |||
| 486 | |||
| 487 | /* | ||
| 488 | * Changes an L2 page descriptor back to a pointer to a physical page | ||
| 489 | */ | ||
| 490 | inline struct page *tf_l2_page_descriptor_to_page(u32 l2_page_descriptor) | ||
| 491 | { | ||
| 492 | return pte_page(l2_page_descriptor & L2_DESCRIPTOR_ADDR_MASK); | ||
| 493 | } | ||
| 494 | |||
| 495 | |||
| 496 | /* | ||
| 497 | * Returns the L1 descriptor for the 1KB-aligned coarse page table. The address | ||
| 498 | * must be in the kernel address space. | ||
| 499 | */ | ||
| 500 | static void tf_get_l2_page_descriptor( | ||
| 501 | u32 *l2_page_descriptor, | ||
| 502 | u32 flags, struct mm_struct *mm) | ||
| 503 | { | ||
| 504 | unsigned long page_vaddr; | ||
| 505 | u32 descriptor; | ||
| 506 | struct page *page; | ||
| 507 | bool unmap_page = false; | ||
| 508 | |||
| 509 | #if 0 | ||
| 510 | dprintk(KERN_INFO | ||
| 511 | "tf_get_l2_page_descriptor():" | ||
| 512 | "*l2_page_descriptor=%x\n", | ||
| 513 | *l2_page_descriptor); | ||
| 514 | #endif | ||
| 515 | |||
| 516 | if (*l2_page_descriptor == L2_DESCRIPTOR_FAULT) | ||
| 517 | return; | ||
| 518 | |||
| 519 | page = (struct page *) (*l2_page_descriptor); | ||
| 520 | |||
| 521 | page_vaddr = (unsigned long) page_address(page); | ||
| 522 | if (page_vaddr == 0) { | ||
| 523 | dprintk(KERN_INFO "page_address returned 0\n"); | ||
| 524 | /* Should we use kmap_atomic(page, KM_USER0) instead ? */ | ||
| 525 | page_vaddr = (unsigned long) kmap(page); | ||
| 526 | if (page_vaddr == 0) { | ||
| 527 | *l2_page_descriptor = L2_DESCRIPTOR_FAULT; | ||
| 528 | dprintk(KERN_ERR "kmap returned 0\n"); | ||
| 529 | return; | ||
| 530 | } | ||
| 531 | unmap_page = true; | ||
| 532 | } | ||
| 533 | |||
| 534 | descriptor = tf_get_l2_descriptor_common(page_vaddr, mm); | ||
| 535 | if (descriptor == 0) { | ||
| 536 | *l2_page_descriptor = L2_DESCRIPTOR_FAULT; | ||
| 537 | return; | ||
| 538 | } | ||
| 539 | descriptor |= L2_PAGE_DESCRIPTOR_BASE; | ||
| 540 | |||
| 541 | descriptor |= (page_to_phys(page) & L2_DESCRIPTOR_ADDR_MASK); | ||
| 542 | |||
| 543 | if (!(flags & TF_SHMEM_TYPE_WRITE)) | ||
| 544 | /* only read access */ | ||
| 545 | descriptor |= L2_PAGE_DESCRIPTOR_AP_APX_READ; | ||
| 546 | else | ||
| 547 | /* read and write access */ | ||
| 548 | descriptor |= L2_PAGE_DESCRIPTOR_AP_APX_READ_WRITE; | ||
| 549 | |||
| 550 | if (unmap_page) | ||
| 551 | kunmap(page); | ||
| 552 | |||
| 553 | *l2_page_descriptor = descriptor; | ||
| 554 | } | ||
| 555 | |||
| 556 | |||
| 557 | /* | ||
| 558 | * Unlocks the physical memory pages | ||
| 559 | * and frees the coarse pages that need to | ||
| 560 | */ | ||
| 561 | void tf_cleanup_shared_memory( | ||
| 562 | struct tf_coarse_page_table_allocation_context *alloc_context, | ||
| 563 | struct tf_shmem_desc *shmem_desc, | ||
| 564 | u32 full_cleanup) | ||
| 565 | { | ||
| 566 | u32 coarse_page_index; | ||
| 567 | |||
| 568 | dprintk(KERN_INFO "tf_cleanup_shared_memory(%p)\n", | ||
| 569 | shmem_desc); | ||
| 570 | |||
| 571 | #ifdef DEBUG_COARSE_TABLES | ||
| 572 | printk(KERN_DEBUG "tf_cleanup_shared_memory " | ||
| 573 | "- number of coarse page tables=%d\n", | ||
| 574 | shmem_desc->coarse_pg_table_count); | ||
| 575 | |||
| 576 | for (coarse_page_index = 0; | ||
| 577 | coarse_page_index < shmem_desc->coarse_pg_table_count; | ||
| 578 | coarse_page_index++) { | ||
| 579 | u32 j; | ||
| 580 | |||
| 581 | printk(KERN_DEBUG " Descriptor=%p address=%p index=%d\n", | ||
| 582 | shmem_desc->coarse_pg_table[coarse_page_index], | ||
| 583 | shmem_desc->coarse_pg_table[coarse_page_index]-> | ||
| 584 | descriptors, | ||
| 585 | coarse_page_index); | ||
| 586 | if (shmem_desc->coarse_pg_table[coarse_page_index] != NULL) { | ||
| 587 | for (j = 0; | ||
| 588 | j < TF_DESCRIPTOR_TABLE_CAPACITY; | ||
| 589 | j += 8) { | ||
| 590 | int k; | ||
| 591 | printk(KERN_DEBUG " "); | ||
| 592 | for (k = j; k < j + 8; k++) | ||
| 593 | printk(KERN_DEBUG "%p ", | ||
| 594 | shmem_desc->coarse_pg_table[ | ||
| 595 | coarse_page_index]-> | ||
| 596 | descriptors); | ||
| 597 | printk(KERN_DEBUG "\n"); | ||
| 598 | } | ||
| 599 | } | ||
| 600 | } | ||
| 601 | printk(KERN_DEBUG "tf_cleanup_shared_memory() - done\n\n"); | ||
| 602 | #endif | ||
| 603 | |||
| 604 | /* Parse the coarse page descriptors */ | ||
| 605 | for (coarse_page_index = 0; | ||
| 606 | coarse_page_index < shmem_desc->coarse_pg_table_count; | ||
| 607 | coarse_page_index++) { | ||
| 608 | u32 j; | ||
| 609 | u32 found = 0; | ||
| 610 | |||
| 611 | /* parse the page descriptors of the coarse page */ | ||
| 612 | for (j = 0; j < TF_DESCRIPTOR_TABLE_CAPACITY; j++) { | ||
| 613 | u32 l2_page_descriptor = (u32) (shmem_desc-> | ||
| 614 | coarse_pg_table[coarse_page_index]-> | ||
| 615 | descriptors[j]); | ||
| 616 | |||
| 617 | if (l2_page_descriptor != L2_DESCRIPTOR_FAULT) { | ||
| 618 | struct page *page = | ||
| 619 | tf_l2_page_descriptor_to_page( | ||
| 620 | l2_page_descriptor); | ||
| 621 | |||
| 622 | if (!PageReserved(page)) | ||
| 623 | SetPageDirty(page); | ||
| 624 | internal_page_cache_release(page); | ||
| 625 | |||
| 626 | found = 1; | ||
| 627 | } else if (found == 1) { | ||
| 628 | break; | ||
| 629 | } | ||
| 630 | } | ||
| 631 | |||
| 632 | /* | ||
| 633 | * Only free the coarse pages of descriptors not preallocated | ||
| 634 | */ | ||
| 635 | if ((shmem_desc->type == TF_SHMEM_TYPE_REGISTERED_SHMEM) || | ||
| 636 | (full_cleanup != 0)) | ||
| 637 | tf_free_coarse_page_table(alloc_context, | ||
| 638 | shmem_desc->coarse_pg_table[coarse_page_index], | ||
| 639 | 0); | ||
| 640 | } | ||
| 641 | |||
| 642 | shmem_desc->coarse_pg_table_count = 0; | ||
| 643 | dprintk(KERN_INFO "tf_cleanup_shared_memory(%p) done\n", | ||
| 644 | shmem_desc); | ||
| 645 | } | ||
| 646 | |||
| 647 | /* | ||
| 648 | * Make sure the coarse pages are allocated. If not allocated, do it. | ||
| 649 | * Locks down the physical memory pages. | ||
| 650 | * Verifies the memory attributes depending on flags. | ||
| 651 | */ | ||
| 652 | int tf_fill_descriptor_table( | ||
| 653 | struct tf_coarse_page_table_allocation_context *alloc_context, | ||
| 654 | struct tf_shmem_desc *shmem_desc, | ||
| 655 | u32 buffer, | ||
| 656 | struct vm_area_struct **vmas, | ||
| 657 | u32 descriptors[TF_MAX_COARSE_PAGES], | ||
| 658 | u32 buffer_size, | ||
| 659 | u32 *buffer_start_offset, | ||
| 660 | bool in_user_space, | ||
| 661 | u32 flags, | ||
| 662 | u32 *descriptor_count) | ||
| 663 | { | ||
| 664 | u32 coarse_page_index; | ||
| 665 | u32 coarse_page_count; | ||
| 666 | u32 page_count; | ||
| 667 | u32 page_shift = 0; | ||
| 668 | int ret = 0; | ||
| 669 | unsigned int info = read_cpuid(CPUID_CACHETYPE); | ||
| 670 | |||
| 671 | dprintk(KERN_INFO "tf_fill_descriptor_table" | ||
| 672 | "(%p, buffer=0x%08X, size=0x%08X, user=%01x " | ||
| 673 | "flags = 0x%08x)\n", | ||
| 674 | shmem_desc, | ||
| 675 | buffer, | ||
| 676 | buffer_size, | ||
| 677 | in_user_space, | ||
| 678 | flags); | ||
| 679 | |||
| 680 | /* | ||
| 681 | * Compute the number of pages | ||
| 682 | * Compute the number of coarse pages | ||
| 683 | * Compute the page offset | ||
| 684 | */ | ||
| 685 | page_count = ((buffer & ~PAGE_MASK) + | ||
| 686 | buffer_size + ~PAGE_MASK) >> PAGE_SHIFT; | ||
| 687 | |||
| 688 | /* check whether the 16k alignment restriction applies */ | ||
| 689 | if (CACHE_S(info) && (CACHE_DSIZE(info) & (1 << 11))) | ||
| 690 | /* | ||
| 691 | * The 16k alignment restriction applies. | ||
| 692 | * Shift data to get them 16k aligned | ||
| 693 | */ | ||
| 694 | page_shift = DESCRIPTOR_V13_12_GET(buffer); | ||
| 695 | page_count += page_shift; | ||
| 696 | |||
| 697 | |||
| 698 | /* | ||
| 699 | * Check the number of pages fit in the coarse pages | ||
| 700 | */ | ||
| 701 | if (page_count > (TF_DESCRIPTOR_TABLE_CAPACITY * | ||
| 702 | TF_MAX_COARSE_PAGES)) { | ||
| 703 | dprintk(KERN_ERR "tf_fill_descriptor_table(%p): " | ||
| 704 | "%u pages required to map shared memory!\n", | ||
| 705 | shmem_desc, page_count); | ||
| 706 | ret = -ENOMEM; | ||
| 707 | goto error; | ||
| 708 | } | ||
| 709 | |||
| 710 | /* coarse page describe 256 pages */ | ||
| 711 | coarse_page_count = ((page_count + | ||
| 712 | TF_DESCRIPTOR_TABLE_CAPACITY_MASK) >> | ||
| 713 | TF_DESCRIPTOR_TABLE_CAPACITY_BIT_SHIFT); | ||
| 714 | |||
| 715 | /* | ||
| 716 | * Compute the buffer offset | ||
| 717 | */ | ||
| 718 | *buffer_start_offset = (buffer & ~PAGE_MASK) | | ||
| 719 | (page_shift << PAGE_SHIFT); | ||
| 720 | |||
| 721 | /* map each coarse page */ | ||
| 722 | for (coarse_page_index = 0; | ||
| 723 | coarse_page_index < coarse_page_count; | ||
| 724 | coarse_page_index++) { | ||
| 725 | u32 j; | ||
| 726 | struct tf_coarse_page_table *coarse_pg_table; | ||
| 727 | |||
| 728 | /* compute a virtual address with appropriate offset */ | ||
| 729 | u32 buffer_offset_vaddr = buffer + | ||
| 730 | (coarse_page_index * TF_MAX_COARSE_PAGE_MAPPED_SIZE); | ||
| 731 | u32 pages_to_get; | ||
| 732 | |||
| 733 | /* | ||
| 734 | * Compute the number of pages left for this coarse page. | ||
| 735 | * Decrement page_count each time | ||
| 736 | */ | ||
| 737 | pages_to_get = (page_count >> | ||
| 738 | TF_DESCRIPTOR_TABLE_CAPACITY_BIT_SHIFT) ? | ||
| 739 | TF_DESCRIPTOR_TABLE_CAPACITY : page_count; | ||
| 740 | page_count -= pages_to_get; | ||
| 741 | |||
| 742 | /* | ||
| 743 | * Check if the coarse page has already been allocated | ||
| 744 | * If not, do it now | ||
| 745 | */ | ||
| 746 | if ((shmem_desc->type == TF_SHMEM_TYPE_REGISTERED_SHMEM) | ||
| 747 | || (shmem_desc->type == | ||
| 748 | TF_SHMEM_TYPE_PM_HIBERNATE)) { | ||
| 749 | coarse_pg_table = tf_alloc_coarse_page_table( | ||
| 750 | alloc_context, | ||
| 751 | TF_PAGE_DESCRIPTOR_TYPE_NORMAL); | ||
| 752 | |||
| 753 | if (coarse_pg_table == NULL) { | ||
| 754 | dprintk(KERN_ERR | ||
| 755 | "tf_fill_descriptor_table(%p): " | ||
| 756 | "tf_alloc_coarse_page_table " | ||
| 757 | "failed for coarse page %d\n", | ||
| 758 | shmem_desc, coarse_page_index); | ||
| 759 | ret = -ENOMEM; | ||
| 760 | goto error; | ||
| 761 | } | ||
| 762 | |||
| 763 | shmem_desc->coarse_pg_table[coarse_page_index] = | ||
| 764 | coarse_pg_table; | ||
| 765 | } else { | ||
| 766 | coarse_pg_table = | ||
| 767 | shmem_desc->coarse_pg_table[coarse_page_index]; | ||
| 768 | } | ||
| 769 | |||
| 770 | /* | ||
| 771 | * The page is not necessarily filled with zeroes. | ||
| 772 | * Set the fault descriptors ( each descriptor is 4 bytes long) | ||
| 773 | */ | ||
| 774 | memset(coarse_pg_table->descriptors, 0x00, | ||
| 775 | TF_DESCRIPTOR_TABLE_CAPACITY * sizeof(u32)); | ||
| 776 | |||
| 777 | if (in_user_space) { | ||
| 778 | int pages; | ||
| 779 | |||
| 780 | /* | ||
| 781 | * TRICK: use pCoarsePageDescriptor->descriptors to | ||
| 782 | * hold the (struct page*) items before getting their | ||
| 783 | * physical address | ||
| 784 | */ | ||
| 785 | down_read(&(current->mm->mmap_sem)); | ||
| 786 | pages = internal_get_user_pages( | ||
| 787 | current, | ||
| 788 | current->mm, | ||
| 789 | buffer_offset_vaddr, | ||
| 790 | /* | ||
| 791 | * page_shift is cleared after retrieving first | ||
| 792 | * coarse page | ||
| 793 | */ | ||
| 794 | (pages_to_get - page_shift), | ||
| 795 | (flags & TF_SHMEM_TYPE_WRITE) ? 1 : 0, | ||
| 796 | 0, | ||
| 797 | (struct page **) (coarse_pg_table->descriptors | ||
| 798 | + page_shift), | ||
| 799 | vmas); | ||
| 800 | up_read(&(current->mm->mmap_sem)); | ||
| 801 | |||
| 802 | if ((pages <= 0) || | ||
| 803 | (pages != (pages_to_get - page_shift))) { | ||
| 804 | dprintk(KERN_ERR "tf_fill_descriptor_table:" | ||
| 805 | " get_user_pages got %d pages while " | ||
| 806 | "trying to get %d pages!\n", | ||
| 807 | pages, pages_to_get - page_shift); | ||
| 808 | ret = -EFAULT; | ||
| 809 | goto error; | ||
| 810 | } | ||
| 811 | |||
| 812 | for (j = page_shift; | ||
| 813 | j < page_shift + pages; | ||
| 814 | j++) { | ||
| 815 | /* Get the actual L2 descriptors */ | ||
| 816 | tf_get_l2_page_descriptor( | ||
| 817 | &coarse_pg_table->descriptors[j], | ||
| 818 | flags, | ||
| 819 | current->mm); | ||
| 820 | /* | ||
| 821 | * Reject Strongly-Ordered or Device Memory | ||
| 822 | */ | ||
| 823 | #define IS_STRONGLY_ORDERED_OR_DEVICE_MEM(x) \ | ||
| 824 | ((((x) & L2_TEX_C_B_MASK) == L2_TEX_C_B_STRONGLY_ORDERED) || \ | ||
| 825 | (((x) & L2_TEX_C_B_MASK) == L2_TEX_C_B_SHARED_DEVICE) || \ | ||
| 826 | (((x) & L2_TEX_C_B_MASK) == L2_TEX_C_B_NON_SHARED_DEVICE)) | ||
| 827 | |||
| 828 | if (IS_STRONGLY_ORDERED_OR_DEVICE_MEM( | ||
| 829 | coarse_pg_table-> | ||
| 830 | descriptors[j])) { | ||
| 831 | dprintk(KERN_ERR | ||
| 832 | "tf_fill_descriptor_table:" | ||
| 833 | " descriptor 0x%08X use " | ||
| 834 | "strongly-ordered or device " | ||
| 835 | "memory. Rejecting!\n", | ||
| 836 | coarse_pg_table-> | ||
| 837 | descriptors[j]); | ||
| 838 | ret = -EFAULT; | ||
| 839 | goto error; | ||
| 840 | } | ||
| 841 | } | ||
| 842 | } else if (is_vmalloc_addr((void *)buffer_offset_vaddr)) { | ||
| 843 | /* Kernel-space memory obtained through vmalloc */ | ||
| 844 | dprintk(KERN_INFO | ||
| 845 | "tf_fill_descriptor_table: " | ||
| 846 | "vmalloc'ed buffer starting at %p\n", | ||
| 847 | (void *)buffer_offset_vaddr); | ||
| 848 | for (j = page_shift; j < pages_to_get; j++) { | ||
| 849 | struct page *page; | ||
| 850 | void *addr = | ||
| 851 | (void *)(buffer_offset_vaddr + | ||
| 852 | (j - page_shift) * PAGE_SIZE); | ||
| 853 | page = vmalloc_to_page(addr); | ||
| 854 | if (page == NULL) { | ||
| 855 | dprintk(KERN_ERR | ||
| 856 | "tf_fill_descriptor_table: " | ||
| 857 | "cannot map %p (vmalloc) " | ||
| 858 | "to page\n", | ||
| 859 | addr); | ||
| 860 | ret = -EFAULT; | ||
| 861 | goto error; | ||
| 862 | } | ||
| 863 | coarse_pg_table->descriptors[j] = (u32)page; | ||
| 864 | get_page(page); | ||
| 865 | |||
| 866 | /* change coarse page "page address" */ | ||
| 867 | tf_get_l2_page_descriptor( | ||
| 868 | &coarse_pg_table->descriptors[j], | ||
| 869 | flags, | ||
| 870 | &init_mm); | ||
| 871 | } | ||
| 872 | } else { | ||
| 873 | /* Kernel-space memory given by a virtual address */ | ||
| 874 | dprintk(KERN_INFO | ||
| 875 | "tf_fill_descriptor_table: " | ||
| 876 | "buffer starting at virtual address %p\n", | ||
| 877 | (void *)buffer_offset_vaddr); | ||
| 878 | for (j = page_shift; j < pages_to_get; j++) { | ||
| 879 | struct page *page; | ||
| 880 | void *addr = | ||
| 881 | (void *)(buffer_offset_vaddr + | ||
| 882 | (j - page_shift) * PAGE_SIZE); | ||
| 883 | page = virt_to_page(addr); | ||
| 884 | if (page == NULL) { | ||
| 885 | dprintk(KERN_ERR | ||
| 886 | "tf_fill_descriptor_table: " | ||
| 887 | "cannot map %p (virtual) " | ||
| 888 | "to page\n", | ||
| 889 | addr); | ||
| 890 | ret = -EFAULT; | ||
| 891 | goto error; | ||
| 892 | } | ||
| 893 | coarse_pg_table->descriptors[j] = (u32)page; | ||
| 894 | get_page(page); | ||
| 895 | |||
| 896 | /* change coarse page "page address" */ | ||
| 897 | tf_get_l2_page_descriptor( | ||
| 898 | &coarse_pg_table->descriptors[j], | ||
| 899 | flags, | ||
| 900 | &init_mm); | ||
| 901 | } | ||
| 902 | } | ||
| 903 | |||
| 904 | dmac_flush_range((void *)coarse_pg_table->descriptors, | ||
| 905 | (void *)(((u32)(coarse_pg_table->descriptors)) + | ||
| 906 | TF_DESCRIPTOR_TABLE_CAPACITY * sizeof(u32))); | ||
| 907 | |||
| 908 | outer_clean_range( | ||
| 909 | __pa(coarse_pg_table->descriptors), | ||
| 910 | __pa(coarse_pg_table->descriptors) + | ||
| 911 | TF_DESCRIPTOR_TABLE_CAPACITY * sizeof(u32)); | ||
| 912 | wmb(); | ||
| 913 | |||
| 914 | /* Update the coarse page table address */ | ||
| 915 | descriptors[coarse_page_index] = | ||
| 916 | tf_get_l1_coarse_descriptor( | ||
| 917 | coarse_pg_table->descriptors); | ||
| 918 | |||
| 919 | /* | ||
| 920 | * The next coarse page has no page shift, reset the | ||
| 921 | * page_shift | ||
| 922 | */ | ||
| 923 | page_shift = 0; | ||
| 924 | } | ||
| 925 | |||
| 926 | *descriptor_count = coarse_page_count; | ||
| 927 | shmem_desc->coarse_pg_table_count = coarse_page_count; | ||
| 928 | |||
| 929 | #ifdef DEBUG_COARSE_TABLES | ||
| 930 | printk(KERN_DEBUG "ntf_fill_descriptor_table - size=0x%08X " | ||
| 931 | "numberOfCoarsePages=%d\n", buffer_size, | ||
| 932 | shmem_desc->coarse_pg_table_count); | ||
| 933 | for (coarse_page_index = 0; | ||
| 934 | coarse_page_index < shmem_desc->coarse_pg_table_count; | ||
| 935 | coarse_page_index++) { | ||
| 936 | u32 j; | ||
| 937 | struct tf_coarse_page_table *coarse_page_table = | ||
| 938 | shmem_desc->coarse_pg_table[coarse_page_index]; | ||
| 939 | |||
| 940 | printk(KERN_DEBUG " Descriptor=%p address=%p index=%d\n", | ||
| 941 | coarse_page_table, | ||
| 942 | coarse_page_table->descriptors, | ||
| 943 | coarse_page_index); | ||
| 944 | for (j = 0; | ||
| 945 | j < TF_DESCRIPTOR_TABLE_CAPACITY; | ||
| 946 | j += 8) { | ||
| 947 | int k; | ||
| 948 | printk(KERN_DEBUG " "); | ||
| 949 | for (k = j; k < j + 8; k++) | ||
| 950 | printk(KERN_DEBUG "0x%08X ", | ||
| 951 | coarse_page_table->descriptors[k]); | ||
| 952 | printk(KERN_DEBUG "\n"); | ||
| 953 | } | ||
| 954 | } | ||
| 955 | printk(KERN_DEBUG "ntf_fill_descriptor_table() - done\n\n"); | ||
| 956 | #endif | ||
| 957 | |||
| 958 | return 0; | ||
| 959 | |||
| 960 | error: | ||
| 961 | tf_cleanup_shared_memory( | ||
| 962 | alloc_context, | ||
| 963 | shmem_desc, | ||
| 964 | 0); | ||
| 965 | |||
| 966 | return ret; | ||
| 967 | } | ||
| 968 | |||
| 969 | |||
| 970 | /*---------------------------------------------------------------------------- | ||
| 971 | * Standard communication operations | ||
| 972 | *----------------------------------------------------------------------------*/ | ||
| 973 | |||
| 974 | u8 *tf_get_description(struct tf_comm *comm) | ||
| 975 | { | ||
| 976 | if (test_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED, &(comm->flags))) | ||
| 977 | return comm->l1_buffer->version_description; | ||
| 978 | |||
| 979 | return NULL; | ||
| 980 | } | ||
| 981 | |||
| 982 | /* | ||
| 983 | * Returns a non-zero value if the specified S-timeout has expired, zero | ||
| 984 | * otherwise. | ||
| 985 | * | ||
| 986 | * The placeholder referenced to by relative_timeout_jiffies gives the relative | ||
| 987 | * timeout from now in jiffies. It is set to zero if the S-timeout has expired, | ||
| 988 | * or to MAX_SCHEDULE_TIMEOUT if the S-timeout is infinite. | ||
| 989 | */ | ||
| 990 | static int tf_test_s_timeout( | ||
| 991 | u64 timeout, | ||
| 992 | signed long *relative_timeout_jiffies) | ||
| 993 | { | ||
| 994 | struct timeval now; | ||
| 995 | u64 time64; | ||
| 996 | |||
| 997 | *relative_timeout_jiffies = 0; | ||
| 998 | |||
| 999 | /* immediate timeout */ | ||
| 1000 | if (timeout == TIME_IMMEDIATE) | ||
| 1001 | return 1; | ||
| 1002 | |||
| 1003 | /* infinite timeout */ | ||
| 1004 | if (timeout == TIME_INFINITE) { | ||
| 1005 | dprintk(KERN_DEBUG "tf_test_s_timeout: " | ||
| 1006 | "timeout is infinite\n"); | ||
| 1007 | *relative_timeout_jiffies = MAX_SCHEDULE_TIMEOUT; | ||
| 1008 | return 0; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | do_gettimeofday(&now); | ||
| 1012 | time64 = now.tv_sec; | ||
| 1013 | /* will not overflow as operations are done on 64bit values */ | ||
| 1014 | time64 = (time64 * 1000) + (now.tv_usec / 1000); | ||
| 1015 | |||
| 1016 | /* timeout expired */ | ||
| 1017 | if (time64 >= timeout) { | ||
| 1018 | dprintk(KERN_DEBUG "tf_test_s_timeout: timeout expired\n"); | ||
| 1019 | return 1; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | /* | ||
| 1023 | * finite timeout, compute relative_timeout_jiffies | ||
| 1024 | */ | ||
| 1025 | /* will not overflow as time64 < timeout */ | ||
| 1026 | timeout -= time64; | ||
| 1027 | |||
| 1028 | /* guarantee *relative_timeout_jiffies is a valid timeout */ | ||
| 1029 | if ((timeout >> 32) != 0) | ||
| 1030 | *relative_timeout_jiffies = MAX_JIFFY_OFFSET; | ||
| 1031 | else | ||
| 1032 | *relative_timeout_jiffies = | ||
| 1033 | msecs_to_jiffies((unsigned int) timeout); | ||
| 1034 | |||
| 1035 | dprintk(KERN_DEBUG "tf_test_s_timeout: timeout is 0x%lx\n", | ||
| 1036 | *relative_timeout_jiffies); | ||
| 1037 | return 0; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | static void tf_copy_answers(struct tf_comm *comm) | ||
| 1041 | { | ||
| 1042 | u32 first_answer; | ||
| 1043 | u32 first_free_answer; | ||
| 1044 | struct tf_answer_struct *answerStructureTemp; | ||
| 1045 | |||
| 1046 | if (test_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED, &(comm->flags))) { | ||
| 1047 | spin_lock(&comm->lock); | ||
| 1048 | first_free_answer = tf_read_reg32( | ||
| 1049 | &comm->l1_buffer->first_free_answer); | ||
| 1050 | first_answer = tf_read_reg32( | ||
| 1051 | &comm->l1_buffer->first_answer); | ||
| 1052 | |||
| 1053 | while (first_answer != first_free_answer) { | ||
| 1054 | /* answer queue not empty */ | ||
| 1055 | union tf_answer sComAnswer; | ||
| 1056 | struct tf_answer_header header; | ||
| 1057 | |||
| 1058 | /* | ||
| 1059 | * the size of the command in words of 32bit, not in | ||
| 1060 | * bytes | ||
| 1061 | */ | ||
| 1062 | u32 command_size; | ||
| 1063 | u32 i; | ||
| 1064 | u32 *temp = (uint32_t *) &header; | ||
| 1065 | |||
| 1066 | dprintk(KERN_INFO | ||
| 1067 | "[pid=%d] tf_copy_answers(%p): " | ||
| 1068 | "Read answers from L1\n", | ||
| 1069 | current->pid, comm); | ||
| 1070 | |||
| 1071 | /* Read the answer header */ | ||
| 1072 | for (i = 0; | ||
| 1073 | i < sizeof(struct tf_answer_header)/sizeof(u32); | ||
| 1074 | i++) | ||
| 1075 | temp[i] = comm->l1_buffer->answer_queue[ | ||
| 1076 | (first_answer + i) % | ||
| 1077 | TF_S_ANSWER_QUEUE_CAPACITY]; | ||
| 1078 | |||
| 1079 | /* Read the answer from the L1_Buffer*/ | ||
| 1080 | command_size = header.message_size + | ||
| 1081 | sizeof(struct tf_answer_header)/sizeof(u32); | ||
| 1082 | temp = (uint32_t *) &sComAnswer; | ||
| 1083 | for (i = 0; i < command_size; i++) | ||
| 1084 | temp[i] = comm->l1_buffer->answer_queue[ | ||
| 1085 | (first_answer + i) % | ||
| 1086 | TF_S_ANSWER_QUEUE_CAPACITY]; | ||
| 1087 | |||
| 1088 | answerStructureTemp = (struct tf_answer_struct *) | ||
| 1089 | sComAnswer.header.operation_id; | ||
| 1090 | |||
| 1091 | tf_dump_answer(&sComAnswer); | ||
| 1092 | |||
| 1093 | memcpy(answerStructureTemp->answer, &sComAnswer, | ||
| 1094 | command_size * sizeof(u32)); | ||
| 1095 | answerStructureTemp->answer_copied = true; | ||
| 1096 | |||
| 1097 | first_answer += command_size; | ||
| 1098 | tf_write_reg32(&comm->l1_buffer->first_answer, | ||
| 1099 | first_answer); | ||
| 1100 | } | ||
| 1101 | spin_unlock(&(comm->lock)); | ||
| 1102 | } | ||
| 1103 | } | ||
| 1104 | |||
| 1105 | static void tf_copy_command( | ||
| 1106 | struct tf_comm *comm, | ||
| 1107 | union tf_command *command, | ||
| 1108 | struct tf_connection *connection, | ||
| 1109 | enum TF_COMMAND_STATE *command_status) | ||
| 1110 | { | ||
| 1111 | if ((test_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED, &(comm->flags))) | ||
| 1112 | && (command != NULL)) { | ||
| 1113 | /* | ||
| 1114 | * Write the message in the message queue. | ||
| 1115 | */ | ||
| 1116 | |||
| 1117 | if (*command_status == TF_COMMAND_STATE_PENDING) { | ||
| 1118 | u32 command_size; | ||
| 1119 | u32 queue_words_count; | ||
| 1120 | u32 i; | ||
| 1121 | u32 first_free_command; | ||
| 1122 | u32 first_command; | ||
| 1123 | |||
| 1124 | spin_lock(&comm->lock); | ||
| 1125 | |||
| 1126 | first_command = tf_read_reg32( | ||
| 1127 | &comm->l1_buffer->first_command); | ||
| 1128 | first_free_command = tf_read_reg32( | ||
| 1129 | &comm->l1_buffer->first_free_command); | ||
| 1130 | |||
| 1131 | queue_words_count = first_free_command - first_command; | ||
| 1132 | command_size = command->header.message_size + | ||
| 1133 | sizeof(struct tf_command_header)/sizeof(u32); | ||
| 1134 | if ((queue_words_count + command_size) < | ||
| 1135 | TF_N_MESSAGE_QUEUE_CAPACITY) { | ||
| 1136 | /* | ||
| 1137 | * Command queue is not full. | ||
| 1138 | * If the Command queue is full, | ||
| 1139 | * the command will be copied at | ||
| 1140 | * another iteration | ||
| 1141 | * of the current function. | ||
| 1142 | */ | ||
| 1143 | |||
| 1144 | /* | ||
| 1145 | * Change the conn state | ||
| 1146 | */ | ||
| 1147 | if (connection == NULL) | ||
| 1148 | goto copy; | ||
| 1149 | |||
| 1150 | spin_lock(&(connection->state_lock)); | ||
| 1151 | |||
| 1152 | if ((connection->state == | ||
| 1153 | TF_CONN_STATE_NO_DEVICE_CONTEXT) | ||
| 1154 | && | ||
| 1155 | (command->header.message_type == | ||
| 1156 | TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT)) { | ||
| 1157 | |||
| 1158 | dprintk(KERN_INFO | ||
| 1159 | "tf_copy_command(%p):" | ||
| 1160 | "Conn state is DEVICE_CONTEXT_SENT\n", | ||
| 1161 | connection); | ||
| 1162 | connection->state = | ||
| 1163 | TF_CONN_STATE_CREATE_DEVICE_CONTEXT_SENT; | ||
| 1164 | } else if ((connection->state != | ||
| 1165 | TF_CONN_STATE_VALID_DEVICE_CONTEXT) | ||
| 1166 | && | ||
| 1167 | (command->header.message_type != | ||
| 1168 | TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT)) { | ||
| 1169 | /* The connection | ||
| 1170 | * is no longer valid. | ||
| 1171 | * We may not send any command on it, | ||
| 1172 | * not even another | ||
| 1173 | * DESTROY_DEVICE_CONTEXT. | ||
| 1174 | */ | ||
| 1175 | dprintk(KERN_INFO | ||
| 1176 | "[pid=%d] tf_copy_command(%p): " | ||
| 1177 | "Connection no longer valid." | ||
| 1178 | "ABORT\n", | ||
| 1179 | current->pid, connection); | ||
| 1180 | *command_status = | ||
| 1181 | TF_COMMAND_STATE_ABORTED; | ||
| 1182 | spin_unlock( | ||
| 1183 | &(connection->state_lock)); | ||
| 1184 | spin_unlock( | ||
| 1185 | &comm->lock); | ||
| 1186 | return; | ||
| 1187 | } else if ( | ||
| 1188 | (command->header.message_type == | ||
| 1189 | TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT) && | ||
| 1190 | (connection->state == | ||
| 1191 | TF_CONN_STATE_VALID_DEVICE_CONTEXT) | ||
| 1192 | ) { | ||
| 1193 | dprintk(KERN_INFO | ||
| 1194 | "[pid=%d] tf_copy_command(%p): " | ||
| 1195 | "Conn state is " | ||
| 1196 | "DESTROY_DEVICE_CONTEXT_SENT\n", | ||
| 1197 | current->pid, connection); | ||
| 1198 | connection->state = | ||
| 1199 | TF_CONN_STATE_DESTROY_DEVICE_CONTEXT_SENT; | ||
| 1200 | } | ||
| 1201 | spin_unlock(&(connection->state_lock)); | ||
| 1202 | copy: | ||
| 1203 | /* | ||
| 1204 | * Copy the command to L1 Buffer | ||
| 1205 | */ | ||
| 1206 | dprintk(KERN_INFO | ||
| 1207 | "[pid=%d] tf_copy_command(%p): " | ||
| 1208 | "Write Message in the queue\n", | ||
| 1209 | current->pid, command); | ||
| 1210 | tf_dump_command(command); | ||
| 1211 | |||
| 1212 | for (i = 0; i < command_size; i++) | ||
| 1213 | comm->l1_buffer->command_queue[ | ||
| 1214 | (first_free_command + i) % | ||
| 1215 | TF_N_MESSAGE_QUEUE_CAPACITY] = | ||
| 1216 | ((uint32_t *) command)[i]; | ||
| 1217 | |||
| 1218 | *command_status = | ||
| 1219 | TF_COMMAND_STATE_SENT; | ||
| 1220 | first_free_command += command_size; | ||
| 1221 | |||
| 1222 | tf_write_reg32( | ||
| 1223 | &comm-> | ||
| 1224 | l1_buffer->first_free_command, | ||
| 1225 | first_free_command); | ||
| 1226 | } | ||
| 1227 | spin_unlock(&comm->lock); | ||
| 1228 | } | ||
| 1229 | } | ||
| 1230 | } | ||
| 1231 | |||
| 1232 | /* | ||
| 1233 | * Sends the specified message through the specified communication channel. | ||
| 1234 | * | ||
| 1235 | * This function sends the command and waits for the answer | ||
| 1236 | * | ||
| 1237 | * Returns zero upon successful completion, or an appropriate error code upon | ||
| 1238 | * failure. | ||
| 1239 | */ | ||
| 1240 | static int tf_send_recv(struct tf_comm *comm, | ||
| 1241 | union tf_command *command, | ||
| 1242 | struct tf_answer_struct *answerStruct, | ||
| 1243 | struct tf_connection *connection, | ||
| 1244 | int bKillable | ||
| 1245 | ) | ||
| 1246 | { | ||
| 1247 | int result; | ||
| 1248 | u64 timeout; | ||
| 1249 | signed long nRelativeTimeoutJiffies; | ||
| 1250 | bool wait_prepared = false; | ||
| 1251 | enum TF_COMMAND_STATE command_status = TF_COMMAND_STATE_PENDING; | ||
| 1252 | DEFINE_WAIT(wait); | ||
| 1253 | #ifdef CONFIG_FREEZER | ||
| 1254 | unsigned long saved_flags; | ||
| 1255 | #endif | ||
| 1256 | dprintk(KERN_INFO "[pid=%d] tf_send_recv(%p)\n", | ||
| 1257 | current->pid, command); | ||
| 1258 | |||
| 1259 | #ifdef CONFIG_TF_ZEBRA | ||
| 1260 | tf_clock_timer_start(); | ||
| 1261 | #endif | ||
| 1262 | |||
| 1263 | #ifdef CONFIG_FREEZER | ||
| 1264 | saved_flags = current->flags; | ||
| 1265 | current->flags |= PF_FREEZER_NOSIG; | ||
| 1266 | #endif | ||
| 1267 | |||
| 1268 | /* | ||
| 1269 | * Read all answers from the answer queue | ||
| 1270 | */ | ||
| 1271 | copy_answers: | ||
| 1272 | tf_copy_answers(comm); | ||
| 1273 | |||
| 1274 | tf_copy_command(comm, command, connection, &command_status); | ||
| 1275 | |||
| 1276 | /* | ||
| 1277 | * Notify all waiting threads | ||
| 1278 | */ | ||
| 1279 | wake_up(&(comm->wait_queue)); | ||
| 1280 | |||
| 1281 | #ifdef CONFIG_FREEZER | ||
| 1282 | if (unlikely(freezing(current))) { | ||
| 1283 | |||
| 1284 | dprintk(KERN_INFO | ||
| 1285 | "Entering refrigerator.\n"); | ||
| 1286 | refrigerator(); | ||
| 1287 | dprintk(KERN_INFO | ||
| 1288 | "Left refrigerator.\n"); | ||
| 1289 | goto copy_answers; | ||
| 1290 | } | ||
| 1291 | #endif | ||
| 1292 | |||
| 1293 | #ifndef CONFIG_PREEMPT | ||
| 1294 | if (need_resched()) | ||
| 1295 | schedule(); | ||
| 1296 | #endif | ||
| 1297 | |||
| 1298 | #ifdef CONFIG_TF_ZEBRA | ||
| 1299 | /* | ||
| 1300 | * Handle RPC (if any) | ||
| 1301 | */ | ||
| 1302 | if (tf_rpc_execute(comm) == RPC_NON_YIELD) | ||
| 1303 | goto schedule_secure_world; | ||
| 1304 | #endif | ||
| 1305 | |||
| 1306 | /* | ||
| 1307 | * Join wait queue | ||
| 1308 | */ | ||
| 1309 | /*dprintk(KERN_INFO "[pid=%d] tf_send_recv(%p): Prepare to wait\n", | ||
| 1310 | current->pid, command);*/ | ||
| 1311 | prepare_to_wait(&comm->wait_queue, &wait, | ||
| 1312 | bKillable ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE); | ||
| 1313 | wait_prepared = true; | ||
| 1314 | |||
| 1315 | /* | ||
| 1316 | * Check if our answer is available | ||
| 1317 | */ | ||
| 1318 | if (command_status == TF_COMMAND_STATE_ABORTED) { | ||
| 1319 | /* Not waiting for an answer, return error code */ | ||
| 1320 | result = -EINTR; | ||
| 1321 | dprintk(KERN_ERR "[pid=%d] tf_send_recv: " | ||
| 1322 | "Command status is ABORTED." | ||
| 1323 | "Exit with 0x%x\n", | ||
| 1324 | current->pid, result); | ||
| 1325 | goto exit; | ||
| 1326 | } | ||
| 1327 | if (answerStruct->answer_copied) { | ||
| 1328 | dprintk(KERN_INFO "[pid=%d] tf_send_recv: " | ||
| 1329 | "Received answer (type 0x%02X)\n", | ||
| 1330 | current->pid, | ||
| 1331 | answerStruct->answer->header.message_type); | ||
| 1332 | result = 0; | ||
| 1333 | goto exit; | ||
| 1334 | } | ||
| 1335 | |||
| 1336 | /* | ||
| 1337 | * Check if a signal is pending | ||
| 1338 | */ | ||
| 1339 | if (bKillable && (sigkill_pending())) { | ||
| 1340 | if (command_status == TF_COMMAND_STATE_PENDING) | ||
| 1341 | /*Command was not sent. */ | ||
| 1342 | result = -EINTR; | ||
| 1343 | else | ||
| 1344 | /* Command was sent but no answer was received yet. */ | ||
| 1345 | result = -EIO; | ||
| 1346 | |||
| 1347 | dprintk(KERN_ERR "[pid=%d] tf_send_recv: " | ||
| 1348 | "Signal Pending. Return error %d\n", | ||
| 1349 | current->pid, result); | ||
| 1350 | goto exit; | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | /* | ||
| 1354 | * Check if secure world is schedulable. It is schedulable if at | ||
| 1355 | * least one of the following conditions holds: | ||
| 1356 | * + it is still initializing (TF_COMM_FLAG_L1_SHARED_ALLOCATED | ||
| 1357 | * is not set); | ||
| 1358 | * + there is a command in the queue; | ||
| 1359 | * + the secure world timeout is zero. | ||
| 1360 | */ | ||
| 1361 | if (test_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED, &(comm->flags))) { | ||
| 1362 | u32 first_free_command; | ||
| 1363 | u32 first_command; | ||
| 1364 | spin_lock(&comm->lock); | ||
| 1365 | first_command = tf_read_reg32( | ||
| 1366 | &comm->l1_buffer->first_command); | ||
| 1367 | first_free_command = tf_read_reg32( | ||
| 1368 | &comm->l1_buffer->first_free_command); | ||
| 1369 | spin_unlock(&comm->lock); | ||
| 1370 | tf_read_timeout(comm, &timeout); | ||
| 1371 | if ((first_free_command == first_command) && | ||
| 1372 | (tf_test_s_timeout(timeout, | ||
| 1373 | &nRelativeTimeoutJiffies) == 0)) | ||
| 1374 | /* | ||
| 1375 | * If command queue is empty and if timeout has not | ||
| 1376 | * expired secure world is not schedulable | ||
| 1377 | */ | ||
| 1378 | goto wait; | ||
| 1379 | } | ||
| 1380 | |||
| 1381 | finish_wait(&comm->wait_queue, &wait); | ||
| 1382 | wait_prepared = false; | ||
| 1383 | |||
| 1384 | /* | ||
| 1385 | * Yield to the Secure World | ||
| 1386 | */ | ||
| 1387 | #ifdef CONFIG_TF_ZEBRA | ||
| 1388 | schedule_secure_world: | ||
| 1389 | #endif | ||
| 1390 | |||
| 1391 | result = tf_schedule_secure_world(comm); | ||
| 1392 | if (result < 0) | ||
| 1393 | goto exit; | ||
| 1394 | goto copy_answers; | ||
| 1395 | |||
| 1396 | wait: | ||
| 1397 | if (bKillable && (sigkill_pending())) { | ||
| 1398 | if (command_status == TF_COMMAND_STATE_PENDING) | ||
| 1399 | result = -EINTR; /* Command was not sent. */ | ||
| 1400 | else | ||
| 1401 | /* Command was sent but no answer was received yet. */ | ||
| 1402 | result = -EIO; | ||
| 1403 | |||
| 1404 | dprintk(KERN_ERR "[pid=%d] tf_send_recv: " | ||
| 1405 | "Signal Pending while waiting. Return error %d\n", | ||
| 1406 | current->pid, result); | ||
| 1407 | goto exit; | ||
| 1408 | } | ||
| 1409 | |||
| 1410 | if (nRelativeTimeoutJiffies == MAX_SCHEDULE_TIMEOUT) | ||
| 1411 | dprintk(KERN_INFO "[pid=%d] tf_send_recv: " | ||
| 1412 | "prepare to sleep infinitely\n", current->pid); | ||
| 1413 | else | ||
| 1414 | dprintk(KERN_INFO "tf_send_recv: " | ||
| 1415 | "prepare to sleep 0x%lx jiffies\n", | ||
| 1416 | nRelativeTimeoutJiffies); | ||
| 1417 | |||
| 1418 | /* go to sleep */ | ||
| 1419 | if (schedule_timeout(nRelativeTimeoutJiffies) == 0) | ||
| 1420 | dprintk(KERN_INFO | ||
| 1421 | "tf_send_recv: timeout expired\n"); | ||
| 1422 | else | ||
| 1423 | dprintk(KERN_INFO | ||
| 1424 | "tf_send_recv: signal delivered\n"); | ||
| 1425 | |||
| 1426 | finish_wait(&comm->wait_queue, &wait); | ||
| 1427 | wait_prepared = false; | ||
| 1428 | goto copy_answers; | ||
| 1429 | |||
| 1430 | exit: | ||
| 1431 | if (wait_prepared) { | ||
| 1432 | finish_wait(&comm->wait_queue, &wait); | ||
| 1433 | wait_prepared = false; | ||
| 1434 | } | ||
| 1435 | |||
| 1436 | #ifdef CONFIG_FREEZER | ||
| 1437 | current->flags &= ~(PF_FREEZER_NOSIG); | ||
| 1438 | current->flags |= (saved_flags & PF_FREEZER_NOSIG); | ||
| 1439 | #endif | ||
| 1440 | |||
| 1441 | return result; | ||
| 1442 | } | ||
| 1443 | |||
| 1444 | /* | ||
| 1445 | * Sends the specified message through the specified communication channel. | ||
| 1446 | * | ||
| 1447 | * This function sends the message and waits for the corresponding answer | ||
| 1448 | * It may return if a signal needs to be delivered. | ||
| 1449 | * | ||
| 1450 | * Returns zero upon successful completion, or an appropriate error code upon | ||
| 1451 | * failure. | ||
| 1452 | */ | ||
| 1453 | int tf_send_receive(struct tf_comm *comm, | ||
| 1454 | union tf_command *command, | ||
| 1455 | union tf_answer *answer, | ||
| 1456 | struct tf_connection *connection, | ||
| 1457 | bool bKillable) | ||
| 1458 | { | ||
| 1459 | int error; | ||
| 1460 | struct tf_answer_struct answerStructure; | ||
| 1461 | #ifdef CONFIG_SMP | ||
| 1462 | long ret_affinity; | ||
| 1463 | cpumask_t saved_cpu_mask; | ||
| 1464 | cpumask_t local_cpu_mask = CPU_MASK_NONE; | ||
| 1465 | #endif | ||
| 1466 | |||
| 1467 | answerStructure.answer = answer; | ||
| 1468 | answerStructure.answer_copied = false; | ||
| 1469 | |||
| 1470 | if (command != NULL) | ||
| 1471 | command->header.operation_id = (u32) &answerStructure; | ||
| 1472 | |||
| 1473 | dprintk(KERN_INFO "tf_send_receive\n"); | ||
| 1474 | |||
| 1475 | #ifdef CONFIG_TF_ZEBRA | ||
| 1476 | if (!test_bit(TF_COMM_FLAG_PA_AVAILABLE, &comm->flags)) { | ||
| 1477 | dprintk(KERN_ERR "tf_send_receive(%p): " | ||
| 1478 | "Secure world not started\n", comm); | ||
| 1479 | |||
| 1480 | return -EFAULT; | ||
| 1481 | } | ||
| 1482 | #endif | ||
| 1483 | |||
| 1484 | if (test_bit(TF_COMM_FLAG_TERMINATING, &(comm->flags)) != 0) { | ||
| 1485 | dprintk(KERN_DEBUG | ||
| 1486 | "tf_send_receive: Flag Terminating is set\n"); | ||
| 1487 | return 0; | ||
| 1488 | } | ||
| 1489 | |||
| 1490 | #ifdef CONFIG_SMP | ||
| 1491 | cpu_set(0, local_cpu_mask); | ||
| 1492 | sched_getaffinity(0, &saved_cpu_mask); | ||
| 1493 | ret_affinity = sched_setaffinity(0, &local_cpu_mask); | ||
| 1494 | if (ret_affinity != 0) | ||
| 1495 | dprintk(KERN_ERR "sched_setaffinity #1 -> 0x%lX", ret_affinity); | ||
| 1496 | #endif | ||
| 1497 | |||
| 1498 | |||
| 1499 | /* | ||
| 1500 | * Send the command | ||
| 1501 | */ | ||
| 1502 | error = tf_send_recv(comm, | ||
| 1503 | command, &answerStructure, connection, bKillable); | ||
| 1504 | |||
| 1505 | if (!bKillable && sigkill_pending()) { | ||
| 1506 | if ((command->header.message_type == | ||
| 1507 | TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT) && | ||
| 1508 | (answer->create_device_context.error_code == | ||
| 1509 | S_SUCCESS)) { | ||
| 1510 | |||
| 1511 | /* | ||
| 1512 | * CREATE_DEVICE_CONTEXT was interrupted. | ||
| 1513 | */ | ||
| 1514 | dprintk(KERN_INFO "tf_send_receive: " | ||
| 1515 | "sending DESTROY_DEVICE_CONTEXT\n"); | ||
| 1516 | answerStructure.answer = answer; | ||
| 1517 | answerStructure.answer_copied = false; | ||
| 1518 | |||
| 1519 | command->header.message_type = | ||
| 1520 | TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT; | ||
| 1521 | command->header.message_size = | ||
| 1522 | (sizeof(struct | ||
| 1523 | tf_command_destroy_device_context) - | ||
| 1524 | sizeof(struct tf_command_header))/sizeof(u32); | ||
| 1525 | command->header.operation_id = | ||
| 1526 | (u32) &answerStructure; | ||
| 1527 | command->destroy_device_context.device_context = | ||
| 1528 | answer->create_device_context. | ||
| 1529 | device_context; | ||
| 1530 | |||
| 1531 | goto destroy_context; | ||
| 1532 | } | ||
| 1533 | } | ||
| 1534 | |||
| 1535 | if (error == 0) { | ||
| 1536 | /* | ||
| 1537 | * tf_send_recv returned Success. | ||
| 1538 | */ | ||
| 1539 | if (command->header.message_type == | ||
| 1540 | TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT) { | ||
| 1541 | spin_lock(&(connection->state_lock)); | ||
| 1542 | connection->state = TF_CONN_STATE_VALID_DEVICE_CONTEXT; | ||
| 1543 | spin_unlock(&(connection->state_lock)); | ||
| 1544 | } else if (command->header.message_type == | ||
| 1545 | TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT) { | ||
| 1546 | spin_lock(&(connection->state_lock)); | ||
| 1547 | connection->state = TF_CONN_STATE_NO_DEVICE_CONTEXT; | ||
| 1548 | spin_unlock(&(connection->state_lock)); | ||
| 1549 | } | ||
| 1550 | } else if (error == -EINTR) { | ||
| 1551 | /* | ||
| 1552 | * No command was sent, return failure. | ||
| 1553 | */ | ||
| 1554 | dprintk(KERN_ERR | ||
| 1555 | "tf_send_receive: " | ||
| 1556 | "tf_send_recv failed (error %d) !\n", | ||
| 1557 | error); | ||
| 1558 | } else if (error == -EIO) { | ||
| 1559 | /* | ||
| 1560 | * A command was sent but its answer is still pending. | ||
| 1561 | */ | ||
| 1562 | |||
| 1563 | /* means bKillable is true */ | ||
| 1564 | dprintk(KERN_ERR | ||
| 1565 | "tf_send_receive: " | ||
| 1566 | "tf_send_recv interrupted (error %d)." | ||
| 1567 | "Send DESTROY_DEVICE_CONTEXT.\n", error); | ||
| 1568 | |||
| 1569 | /* Send the DESTROY_DEVICE_CONTEXT. */ | ||
| 1570 | answerStructure.answer = answer; | ||
| 1571 | answerStructure.answer_copied = false; | ||
| 1572 | |||
| 1573 | command->header.message_type = | ||
| 1574 | TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT; | ||
| 1575 | command->header.message_size = | ||
| 1576 | (sizeof(struct tf_command_destroy_device_context) - | ||
| 1577 | sizeof(struct tf_command_header))/sizeof(u32); | ||
| 1578 | command->header.operation_id = | ||
| 1579 | (u32) &answerStructure; | ||
| 1580 | command->destroy_device_context.device_context = | ||
| 1581 | connection->device_context; | ||
| 1582 | |||
| 1583 | error = tf_send_recv(comm, | ||
| 1584 | command, &answerStructure, connection, false); | ||
| 1585 | if (error == -EINTR) { | ||
| 1586 | /* | ||
| 1587 | * Another thread already sent | ||
| 1588 | * DESTROY_DEVICE_CONTEXT. | ||
| 1589 | * We must still wait for the answer | ||
| 1590 | * to the original command. | ||
| 1591 | */ | ||
| 1592 | command = NULL; | ||
| 1593 | goto destroy_context; | ||
| 1594 | } else { | ||
| 1595 | /* An answer was received. | ||
| 1596 | * Check if it is the answer | ||
| 1597 | * to the DESTROY_DEVICE_CONTEXT. | ||
| 1598 | */ | ||
| 1599 | spin_lock(&comm->lock); | ||
| 1600 | if (answer->header.message_type != | ||
| 1601 | TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT) { | ||
| 1602 | answerStructure.answer_copied = false; | ||
| 1603 | } | ||
| 1604 | spin_unlock(&comm->lock); | ||
| 1605 | if (!answerStructure.answer_copied) { | ||
| 1606 | /* Answer to DESTROY_DEVICE_CONTEXT | ||
| 1607 | * was not yet received. | ||
| 1608 | * Wait for the answer. | ||
| 1609 | */ | ||
| 1610 | dprintk(KERN_INFO | ||
| 1611 | "[pid=%d] tf_send_receive:" | ||
| 1612 | "Answer to DESTROY_DEVICE_CONTEXT" | ||
| 1613 | "not yet received.Retry\n", | ||
| 1614 | current->pid); | ||
| 1615 | command = NULL; | ||
| 1616 | goto destroy_context; | ||
| 1617 | } | ||
| 1618 | } | ||
| 1619 | } | ||
| 1620 | |||
| 1621 | dprintk(KERN_INFO "tf_send_receive(): Message answer ready\n"); | ||
| 1622 | goto exit; | ||
| 1623 | |||
| 1624 | destroy_context: | ||
| 1625 | error = tf_send_recv(comm, | ||
| 1626 | command, &answerStructure, connection, false); | ||
| 1627 | |||
| 1628 | /* | ||
| 1629 | * tf_send_recv cannot return an error because | ||
| 1630 | * it's not killable and not within a connection | ||
| 1631 | */ | ||
| 1632 | BUG_ON(error != 0); | ||
| 1633 | |||
| 1634 | /* Reset the state, so a new CREATE DEVICE CONTEXT can be sent */ | ||
| 1635 | spin_lock(&(connection->state_lock)); | ||
| 1636 | connection->state = TF_CONN_STATE_NO_DEVICE_CONTEXT; | ||
| 1637 | spin_unlock(&(connection->state_lock)); | ||
| 1638 | |||
| 1639 | exit: | ||
| 1640 | |||
| 1641 | #ifdef CONFIG_SMP | ||
| 1642 | ret_affinity = sched_setaffinity(0, &saved_cpu_mask); | ||
| 1643 | if (ret_affinity != 0) | ||
| 1644 | dprintk(KERN_ERR "sched_setaffinity #2 -> 0x%lX", ret_affinity); | ||
| 1645 | #endif | ||
| 1646 | return error; | ||
| 1647 | } | ||
| 1648 | |||
| 1649 | /*---------------------------------------------------------------------------- | ||
| 1650 | * Power management | ||
| 1651 | *----------------------------------------------------------------------------*/ | ||
| 1652 | |||
| 1653 | |||
| 1654 | /* | ||
| 1655 | * Handles all the power management calls. | ||
| 1656 | * The operation is the type of power management | ||
| 1657 | * operation to be performed. | ||
| 1658 | * | ||
| 1659 | * This routine will only return if a failure occured or if | ||
| 1660 | * the required opwer management is of type "resume". | ||
| 1661 | * "Hibernate" and "Shutdown" should lock when doing the | ||
| 1662 | * corresponding SMC to the Secure World | ||
| 1663 | */ | ||
| 1664 | int tf_power_management(struct tf_comm *comm, | ||
| 1665 | enum TF_POWER_OPERATION operation) | ||
| 1666 | { | ||
| 1667 | u32 status; | ||
| 1668 | int error = 0; | ||
| 1669 | |||
| 1670 | dprintk(KERN_INFO "tf_power_management(%d)\n", operation); | ||
| 1671 | |||
| 1672 | #ifdef CONFIG_TF_ZEBRA | ||
| 1673 | if (!test_bit(TF_COMM_FLAG_PA_AVAILABLE, &comm->flags)) { | ||
| 1674 | dprintk(KERN_INFO "tf_power_management(%p): " | ||
| 1675 | "succeeded (not started)\n", comm); | ||
| 1676 | |||
| 1677 | return 0; | ||
| 1678 | } | ||
| 1679 | #endif | ||
| 1680 | |||
| 1681 | status = ((tf_read_reg32(&(comm->l1_buffer->status_s)) | ||
| 1682 | & TF_STATUS_POWER_STATE_MASK) | ||
| 1683 | >> TF_STATUS_POWER_STATE_SHIFT); | ||
| 1684 | |||
| 1685 | switch (operation) { | ||
| 1686 | case TF_POWER_OPERATION_SHUTDOWN: | ||
| 1687 | switch (status) { | ||
| 1688 | case TF_POWER_MODE_ACTIVE: | ||
| 1689 | error = tf_pm_shutdown(comm); | ||
| 1690 | |||
| 1691 | if (error) { | ||
| 1692 | dprintk(KERN_ERR "tf_power_management(): " | ||
| 1693 | "Failed with error code 0x%08x\n", | ||
| 1694 | error); | ||
| 1695 | goto error; | ||
| 1696 | } | ||
| 1697 | break; | ||
| 1698 | |||
| 1699 | default: | ||
| 1700 | goto not_allowed; | ||
| 1701 | } | ||
| 1702 | break; | ||
| 1703 | |||
| 1704 | case TF_POWER_OPERATION_HIBERNATE: | ||
| 1705 | switch (status) { | ||
| 1706 | case TF_POWER_MODE_ACTIVE: | ||
| 1707 | error = tf_pm_hibernate(comm); | ||
| 1708 | |||
| 1709 | if (error) { | ||
| 1710 | dprintk(KERN_ERR "tf_power_management(): " | ||
| 1711 | "Failed with error code 0x%08x\n", | ||
| 1712 | error); | ||
| 1713 | goto error; | ||
| 1714 | } | ||
| 1715 | break; | ||
| 1716 | |||
| 1717 | default: | ||
| 1718 | goto not_allowed; | ||
| 1719 | } | ||
| 1720 | break; | ||
| 1721 | |||
| 1722 | case TF_POWER_OPERATION_RESUME: | ||
| 1723 | error = tf_pm_resume(comm); | ||
| 1724 | |||
| 1725 | if (error != 0) { | ||
| 1726 | dprintk(KERN_ERR "tf_power_management(): " | ||
| 1727 | "Failed with error code 0x%08x\n", | ||
| 1728 | error); | ||
| 1729 | goto error; | ||
| 1730 | } | ||
| 1731 | break; | ||
| 1732 | } | ||
| 1733 | |||
| 1734 | dprintk(KERN_INFO "tf_power_management(): succeeded\n"); | ||
| 1735 | return 0; | ||
| 1736 | |||
| 1737 | not_allowed: | ||
| 1738 | dprintk(KERN_ERR "tf_power_management(): " | ||
| 1739 | "Power command not allowed in current " | ||
| 1740 | "Secure World state %d\n", status); | ||
| 1741 | error = -ENOTTY; | ||
| 1742 | error: | ||
| 1743 | return error; | ||
| 1744 | } | ||
| 1745 | |||
diff --git a/security/tf_driver/tf_comm.h b/security/tf_driver/tf_comm.h new file mode 100644 index 00000000000..8921dc1d1be --- /dev/null +++ b/security/tf_driver/tf_comm.h | |||
| @@ -0,0 +1,202 @@ | |||
| 1 | /** | ||
| 2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 17 | * MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef __TF_COMM_H__ | ||
| 21 | #define __TF_COMM_H__ | ||
| 22 | |||
| 23 | #include "tf_defs.h" | ||
| 24 | #include "tf_protocol.h" | ||
| 25 | |||
| 26 | /*---------------------------------------------------------------------------- | ||
| 27 | * Misc | ||
| 28 | *----------------------------------------------------------------------------*/ | ||
| 29 | |||
| 30 | void tf_set_current_time(struct tf_comm *comm); | ||
| 31 | |||
| 32 | /* | ||
| 33 | * Atomic accesses to 32-bit variables in the L1 Shared buffer | ||
| 34 | */ | ||
| 35 | static inline u32 tf_read_reg32(const u32 *comm_buffer) | ||
| 36 | { | ||
| 37 | u32 result; | ||
| 38 | |||
| 39 | __asm__ __volatile__("@ tf_read_reg32\n" | ||
| 40 | "ldrex %0, [%1]\n" | ||
| 41 | : "=&r" (result) | ||
| 42 | : "r" (comm_buffer) | ||
| 43 | ); | ||
| 44 | |||
| 45 | return result; | ||
| 46 | } | ||
| 47 | |||
| 48 | static inline void tf_write_reg32(void *comm_buffer, u32 value) | ||
| 49 | { | ||
| 50 | u32 tmp; | ||
| 51 | |||
| 52 | __asm__ __volatile__("@ tf_write_reg32\n" | ||
| 53 | "1: ldrex %0, [%2]\n" | ||
| 54 | " strex %0, %1, [%2]\n" | ||
| 55 | " teq %0, #0\n" | ||
| 56 | " bne 1b" | ||
| 57 | : "=&r" (tmp) | ||
| 58 | : "r" (value), "r" (comm_buffer) | ||
| 59 | : "cc" | ||
| 60 | ); | ||
| 61 | } | ||
| 62 | |||
| 63 | /* | ||
| 64 | * Atomic accesses to 64-bit variables in the L1 Shared buffer | ||
| 65 | */ | ||
| 66 | static inline u64 tf_read_reg64(void *comm_buffer) | ||
| 67 | { | ||
| 68 | u64 result; | ||
| 69 | |||
| 70 | __asm__ __volatile__("@ tf_read_reg64\n" | ||
| 71 | "ldrexd %0, [%1]\n" | ||
| 72 | : "=&r" (result) | ||
| 73 | : "r" (comm_buffer) | ||
| 74 | ); | ||
| 75 | |||
| 76 | return result; | ||
| 77 | } | ||
| 78 | |||
| 79 | static inline void tf_write_reg64(void *comm_buffer, u64 value) | ||
| 80 | { | ||
| 81 | u64 tmp; | ||
| 82 | |||
| 83 | __asm__ __volatile__("@ tf_write_reg64\n" | ||
| 84 | "1: ldrexd %0, [%2]\n" | ||
| 85 | " strexd %0, %1, [%2]\n" | ||
| 86 | " teq %0, #0\n" | ||
| 87 | " bne 1b" | ||
| 88 | : "=&r" (tmp) | ||
| 89 | : "r" (value), "r" (comm_buffer) | ||
| 90 | : "cc" | ||
| 91 | ); | ||
| 92 | } | ||
| 93 | |||
| 94 | /*---------------------------------------------------------------------------- | ||
| 95 | * SMC operations | ||
| 96 | *----------------------------------------------------------------------------*/ | ||
| 97 | |||
| 98 | /* RPC return values */ | ||
| 99 | #define RPC_NO 0x00 /* No RPC to execute */ | ||
| 100 | #define RPC_YIELD 0x01 /* Yield RPC */ | ||
| 101 | #define RPC_NON_YIELD 0x02 /* non-Yield RPC */ | ||
| 102 | |||
| 103 | int tf_rpc_execute(struct tf_comm *comm); | ||
| 104 | |||
| 105 | /*---------------------------------------------------------------------------- | ||
| 106 | * Shared memory related operations | ||
| 107 | *----------------------------------------------------------------------------*/ | ||
| 108 | |||
| 109 | #define L1_DESCRIPTOR_FAULT (0x00000000) | ||
| 110 | #define L2_DESCRIPTOR_FAULT (0x00000000) | ||
| 111 | |||
| 112 | #define L2_DESCRIPTOR_ADDR_MASK (0xFFFFF000) | ||
| 113 | |||
| 114 | #define DESCRIPTOR_V13_12_MASK (0x3 << PAGE_SHIFT) | ||
| 115 | #define DESCRIPTOR_V13_12_GET(a) ((a & DESCRIPTOR_V13_12_MASK) >> PAGE_SHIFT) | ||
| 116 | |||
| 117 | struct tf_coarse_page_table *tf_alloc_coarse_page_table( | ||
| 118 | struct tf_coarse_page_table_allocation_context *alloc_context, | ||
| 119 | u32 type); | ||
| 120 | |||
| 121 | void tf_free_coarse_page_table( | ||
| 122 | struct tf_coarse_page_table_allocation_context *alloc_context, | ||
| 123 | struct tf_coarse_page_table *coarse_pg_table, | ||
| 124 | int force); | ||
| 125 | |||
| 126 | void tf_init_coarse_page_table_allocator( | ||
| 127 | struct tf_coarse_page_table_allocation_context *alloc_context); | ||
| 128 | |||
| 129 | void tf_release_coarse_page_table_allocator( | ||
| 130 | struct tf_coarse_page_table_allocation_context *alloc_context); | ||
| 131 | |||
| 132 | struct page *tf_l2_page_descriptor_to_page(u32 l2_page_descriptor); | ||
| 133 | |||
| 134 | u32 tf_get_l2_descriptor_common(u32 vaddr, struct mm_struct *mm); | ||
| 135 | |||
| 136 | void tf_cleanup_shared_memory( | ||
| 137 | struct tf_coarse_page_table_allocation_context *alloc_context, | ||
| 138 | struct tf_shmem_desc *shmem_desc, | ||
| 139 | u32 full_cleanup); | ||
| 140 | |||
| 141 | int tf_fill_descriptor_table( | ||
| 142 | struct tf_coarse_page_table_allocation_context *alloc_context, | ||
| 143 | struct tf_shmem_desc *shmem_desc, | ||
| 144 | u32 buffer, | ||
| 145 | struct vm_area_struct **vmas, | ||
| 146 | u32 descriptors[TF_MAX_COARSE_PAGES], | ||
| 147 | u32 buffer_size, | ||
| 148 | u32 *buffer_start_offset, | ||
| 149 | bool in_user_space, | ||
| 150 | u32 flags, | ||
| 151 | u32 *descriptor_count); | ||
| 152 | |||
| 153 | /*---------------------------------------------------------------------------- | ||
| 154 | * Standard communication operations | ||
| 155 | *----------------------------------------------------------------------------*/ | ||
| 156 | |||
| 157 | int tf_schedule_secure_world(struct tf_comm *comm); | ||
| 158 | |||
| 159 | int tf_send_receive( | ||
| 160 | struct tf_comm *comm, | ||
| 161 | union tf_command *command, | ||
| 162 | union tf_answer *answer, | ||
| 163 | struct tf_connection *connection, | ||
| 164 | bool bKillable); | ||
| 165 | |||
| 166 | |||
| 167 | /** | ||
| 168 | * get a pointer to the secure world description. | ||
| 169 | * This points directly into the L1 shared buffer | ||
| 170 | * and is valid only once the communication has | ||
| 171 | * been initialized | ||
| 172 | **/ | ||
| 173 | u8 *tf_get_description(struct tf_comm *comm); | ||
| 174 | |||
| 175 | /*---------------------------------------------------------------------------- | ||
| 176 | * Power management | ||
| 177 | *----------------------------------------------------------------------------*/ | ||
| 178 | |||
| 179 | enum TF_POWER_OPERATION { | ||
| 180 | TF_POWER_OPERATION_HIBERNATE = 1, | ||
| 181 | TF_POWER_OPERATION_SHUTDOWN = 2, | ||
| 182 | TF_POWER_OPERATION_RESUME = 3, | ||
| 183 | }; | ||
| 184 | |||
| 185 | int tf_pm_hibernate(struct tf_comm *comm); | ||
| 186 | int tf_pm_resume(struct tf_comm *comm); | ||
| 187 | int tf_pm_shutdown(struct tf_comm *comm); | ||
| 188 | |||
| 189 | int tf_power_management(struct tf_comm *comm, | ||
| 190 | enum TF_POWER_OPERATION operation); | ||
| 191 | |||
| 192 | |||
| 193 | /*---------------------------------------------------------------------------- | ||
| 194 | * Communication initialization and termination | ||
| 195 | *----------------------------------------------------------------------------*/ | ||
| 196 | |||
| 197 | int tf_init(struct tf_comm *comm); | ||
| 198 | |||
| 199 | void tf_terminate(struct tf_comm *comm); | ||
| 200 | |||
| 201 | |||
| 202 | #endif /* __TF_COMM_H__ */ | ||
diff --git a/security/tf_driver/tf_comm_tz.c b/security/tf_driver/tf_comm_tz.c new file mode 100644 index 00000000000..4c89de84acc --- /dev/null +++ b/security/tf_driver/tf_comm_tz.c | |||
| @@ -0,0 +1,885 @@ | |||
| 1 | /** | ||
| 2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 17 | * MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <asm/div64.h> | ||
| 21 | #include <asm/system.h> | ||
| 22 | #include <linux/version.h> | ||
| 23 | #include <asm/cputype.h> | ||
| 24 | #include <linux/interrupt.h> | ||
| 25 | #include <linux/page-flags.h> | ||
| 26 | #include <linux/pagemap.h> | ||
| 27 | #include <linux/vmalloc.h> | ||
| 28 | #include <linux/jiffies.h> | ||
| 29 | |||
| 30 | #include "tf_defs.h" | ||
| 31 | #include "tf_comm.h" | ||
| 32 | #include "tf_protocol.h" | ||
| 33 | #include "tf_util.h" | ||
| 34 | #include "tf_conn.h" | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Structure common to all SMC operations | ||
| 38 | */ | ||
| 39 | struct tf_generic_smc { | ||
| 40 | u32 reg0; | ||
| 41 | u32 reg1; | ||
| 42 | u32 reg2; | ||
| 43 | u32 reg3; | ||
| 44 | u32 reg4; | ||
| 45 | }; | ||
| 46 | |||
| 47 | /*---------------------------------------------------------------------------- | ||
| 48 | * SMC operations | ||
| 49 | *----------------------------------------------------------------------------*/ | ||
| 50 | |||
| 51 | static inline void tf_smc_generic_call( | ||
| 52 | struct tf_generic_smc *generic_smc) | ||
| 53 | { | ||
| 54 | #ifdef CONFIG_SMP | ||
| 55 | long ret; | ||
| 56 | cpumask_t saved_cpu_mask; | ||
| 57 | cpumask_t local_cpu_mask = CPU_MASK_NONE; | ||
| 58 | |||
| 59 | cpu_set(0, local_cpu_mask); | ||
| 60 | sched_getaffinity(0, &saved_cpu_mask); | ||
| 61 | ret = sched_setaffinity(0, &local_cpu_mask); | ||
| 62 | if (ret != 0) | ||
| 63 | dprintk(KERN_ERR "sched_setaffinity #1 -> 0x%lX", ret); | ||
| 64 | #endif | ||
| 65 | |||
| 66 | __asm__ volatile( | ||
| 67 | "mov r0, %2\n" | ||
| 68 | "mov r1, %3\n" | ||
| 69 | "mov r2, %4\n" | ||
| 70 | "mov r3, %5\n" | ||
| 71 | "mov r4, %6\n" | ||
| 72 | ".word 0xe1600070 @ SMC 0\n" | ||
| 73 | "mov %0, r0\n" | ||
| 74 | "mov %1, r1\n" | ||
| 75 | : "=r" (generic_smc->reg0), "=r" (generic_smc->reg1) | ||
| 76 | : "r" (generic_smc->reg0), "r" (generic_smc->reg1), | ||
| 77 | "r" (generic_smc->reg2), "r" (generic_smc->reg3), | ||
| 78 | "r" (generic_smc->reg4) | ||
| 79 | : "r0", "r1", "r2", "r3", "r4"); | ||
| 80 | |||
| 81 | #ifdef CONFIG_SMP | ||
| 82 | ret = sched_setaffinity(0, &saved_cpu_mask); | ||
| 83 | if (ret != 0) | ||
| 84 | dprintk(KERN_ERR "sched_setaffinity #2 -> 0x%lX", ret); | ||
| 85 | #endif | ||
| 86 | } | ||
| 87 | |||
| 88 | /* | ||
| 89 | * Calls the get protocol version SMC. | ||
| 90 | * Fills the parameter pProtocolVersion with the version number returned by the | ||
| 91 | * SMC | ||
| 92 | */ | ||
| 93 | static inline void tf_smc_get_protocol_version(u32 *protocol_version) | ||
| 94 | { | ||
| 95 | struct tf_generic_smc generic_smc; | ||
| 96 | |||
| 97 | generic_smc.reg0 = TF_SMC_GET_PROTOCOL_VERSION; | ||
| 98 | generic_smc.reg1 = 0; | ||
| 99 | generic_smc.reg2 = 0; | ||
| 100 | generic_smc.reg3 = 0; | ||
| 101 | generic_smc.reg4 = 0; | ||
| 102 | |||
| 103 | tf_smc_generic_call(&generic_smc); | ||
| 104 | *protocol_version = generic_smc.reg1; | ||
| 105 | } | ||
| 106 | |||
| 107 | |||
| 108 | /* | ||
| 109 | * Calls the init SMC with the specified parameters. | ||
| 110 | * Returns zero upon successful completion, or an appropriate error code upon | ||
| 111 | * failure. | ||
| 112 | */ | ||
| 113 | static inline int tf_smc_init(u32 shared_page_descriptor) | ||
| 114 | { | ||
| 115 | struct tf_generic_smc generic_smc; | ||
| 116 | |||
| 117 | generic_smc.reg0 = TF_SMC_INIT; | ||
| 118 | /* Descriptor for the layer 1 shared buffer */ | ||
| 119 | generic_smc.reg1 = shared_page_descriptor; | ||
| 120 | generic_smc.reg2 = 0; | ||
| 121 | generic_smc.reg3 = 0; | ||
| 122 | generic_smc.reg4 = 0; | ||
| 123 | |||
| 124 | tf_smc_generic_call(&generic_smc); | ||
| 125 | if (generic_smc.reg0 != S_SUCCESS) | ||
| 126 | printk(KERN_ERR "tf_smc_init:" | ||
| 127 | " r0=0x%08X upon return (expected 0x%08X)!\n", | ||
| 128 | generic_smc.reg0, | ||
| 129 | S_SUCCESS); | ||
| 130 | |||
| 131 | return generic_smc.reg0; | ||
| 132 | } | ||
| 133 | |||
| 134 | |||
| 135 | /* | ||
| 136 | * Calls the reset irq SMC. | ||
| 137 | */ | ||
| 138 | static inline void tf_smc_reset_irq(void) | ||
| 139 | { | ||
| 140 | struct tf_generic_smc generic_smc; | ||
| 141 | |||
| 142 | generic_smc.reg0 = TF_SMC_RESET_IRQ; | ||
| 143 | generic_smc.reg1 = 0; | ||
| 144 | generic_smc.reg2 = 0; | ||
| 145 | generic_smc.reg3 = 0; | ||
| 146 | generic_smc.reg4 = 0; | ||
| 147 | |||
| 148 | tf_smc_generic_call(&generic_smc); | ||
| 149 | } | ||
| 150 | |||
| 151 | |||
| 152 | /* | ||
| 153 | * Calls the WAKE_UP SMC. | ||
| 154 | * Returns zero upon successful completion, or an appropriate error code upon | ||
| 155 | * failure. | ||
| 156 | */ | ||
| 157 | static inline int tf_smc_wake_up(u32 l1_shared_buffer_descriptor, | ||
| 158 | u32 shared_mem_start_offset, | ||
| 159 | u32 shared_mem_size) | ||
| 160 | { | ||
| 161 | struct tf_generic_smc generic_smc; | ||
| 162 | |||
| 163 | generic_smc.reg0 = TF_SMC_WAKE_UP; | ||
| 164 | generic_smc.reg1 = shared_mem_start_offset; | ||
| 165 | /* long form command */ | ||
| 166 | generic_smc.reg2 = shared_mem_size | 0x80000000; | ||
| 167 | generic_smc.reg3 = l1_shared_buffer_descriptor; | ||
| 168 | generic_smc.reg4 = 0; | ||
| 169 | |||
| 170 | tf_smc_generic_call(&generic_smc); | ||
| 171 | |||
| 172 | if (generic_smc.reg0 != S_SUCCESS) | ||
| 173 | printk(KERN_ERR "tf_smc_wake_up:" | ||
| 174 | " r0=0x%08X upon return (expected 0x%08X)!\n", | ||
| 175 | generic_smc.reg0, | ||
| 176 | S_SUCCESS); | ||
| 177 | |||
| 178 | return generic_smc.reg0; | ||
| 179 | } | ||
| 180 | |||
| 181 | /* | ||
| 182 | * Calls the N-Yield SMC. | ||
| 183 | */ | ||
| 184 | static inline void tf_smc_nyield(void) | ||
| 185 | { | ||
| 186 | struct tf_generic_smc generic_smc; | ||
| 187 | |||
| 188 | generic_smc.reg0 = TF_SMC_N_YIELD; | ||
| 189 | generic_smc.reg1 = 0; | ||
| 190 | generic_smc.reg2 = 0; | ||
| 191 | generic_smc.reg3 = 0; | ||
| 192 | generic_smc.reg4 = 0; | ||
| 193 | |||
| 194 | tf_smc_generic_call(&generic_smc); | ||
| 195 | } | ||
| 196 | |||
| 197 | /* Yields the Secure World */ | ||
| 198 | int tf_schedule_secure_world(struct tf_comm *comm) | ||
| 199 | { | ||
| 200 | tf_set_current_time(comm); | ||
| 201 | |||
| 202 | /* yield to the Secure World */ | ||
| 203 | tf_smc_nyield(); | ||
| 204 | |||
| 205 | return 0; | ||
| 206 | } | ||
| 207 | |||
| 208 | /* | ||
| 209 | * Returns the L2 descriptor for the specified user page. | ||
| 210 | */ | ||
| 211 | |||
| 212 | #define L2_INIT_DESCRIPTOR_BASE (0x00000003) | ||
| 213 | #define L2_INIT_DESCRIPTOR_V13_12_SHIFT (4) | ||
| 214 | |||
| 215 | static u32 tf_get_l2init_descriptor(u32 vaddr) | ||
| 216 | { | ||
| 217 | struct page *page; | ||
| 218 | u32 paddr; | ||
| 219 | u32 descriptor; | ||
| 220 | |||
| 221 | descriptor = L2_INIT_DESCRIPTOR_BASE; | ||
| 222 | |||
| 223 | /* get physical address and add to descriptor */ | ||
| 224 | page = virt_to_page(vaddr); | ||
| 225 | paddr = page_to_phys(page); | ||
| 226 | descriptor |= (paddr & L2_DESCRIPTOR_ADDR_MASK); | ||
| 227 | |||
| 228 | /* Add virtual address v[13:12] bits to descriptor */ | ||
| 229 | descriptor |= (DESCRIPTOR_V13_12_GET(vaddr) | ||
| 230 | << L2_INIT_DESCRIPTOR_V13_12_SHIFT); | ||
| 231 | |||
| 232 | descriptor |= tf_get_l2_descriptor_common(vaddr, &init_mm); | ||
| 233 | |||
| 234 | |||
| 235 | return descriptor; | ||
| 236 | } | ||
| 237 | |||
| 238 | |||
| 239 | /*---------------------------------------------------------------------------- | ||
| 240 | * Power management | ||
| 241 | *----------------------------------------------------------------------------*/ | ||
| 242 | |||
| 243 | /* | ||
| 244 | * Free the memory used by the W3B buffer for the specified comm. | ||
| 245 | * This function does nothing if no W3B buffer is allocated for the device. | ||
| 246 | */ | ||
| 247 | static inline void tf_free_w3b(struct tf_comm *comm) | ||
| 248 | { | ||
| 249 | tf_cleanup_shared_memory( | ||
| 250 | &(comm->w3b_cpt_alloc_context), | ||
| 251 | &(comm->w3b_shmem_desc), | ||
| 252 | 0); | ||
| 253 | |||
| 254 | tf_release_coarse_page_table_allocator(&(comm->w3b_cpt_alloc_context)); | ||
| 255 | |||
| 256 | internal_vfree((void *)comm->w3b); | ||
| 257 | comm->w3b = 0; | ||
| 258 | comm->w3b_shmem_size = 0; | ||
| 259 | clear_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags)); | ||
| 260 | } | ||
| 261 | |||
| 262 | |||
| 263 | /* | ||
| 264 | * Allocates the W3B buffer for the specified comm. | ||
| 265 | * Returns zero upon successful completion, or an appropriate error code upon | ||
| 266 | * failure. | ||
| 267 | */ | ||
| 268 | static inline int tf_allocate_w3b(struct tf_comm *comm) | ||
| 269 | { | ||
| 270 | int error; | ||
| 271 | u32 flags; | ||
| 272 | u32 config_flag_s; | ||
| 273 | u32 *w3b_descriptors; | ||
| 274 | u32 w3b_descriptor_count; | ||
| 275 | u32 w3b_current_size; | ||
| 276 | |||
| 277 | config_flag_s = tf_read_reg32(&comm->l1_buffer->config_flag_s); | ||
| 278 | |||
| 279 | retry: | ||
| 280 | if ((test_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags))) == 0) { | ||
| 281 | /* | ||
| 282 | * Initialize the shared memory for the W3B | ||
| 283 | */ | ||
| 284 | tf_init_coarse_page_table_allocator( | ||
| 285 | &comm->w3b_cpt_alloc_context); | ||
| 286 | } else { | ||
| 287 | /* | ||
| 288 | * The W3B is allocated but do we have to reallocate a bigger | ||
| 289 | * one? | ||
| 290 | */ | ||
| 291 | /* Check H bit */ | ||
| 292 | if ((config_flag_s & (1<<4)) != 0) { | ||
| 293 | /* The size of the W3B may change after SMC_INIT */ | ||
| 294 | /* Read the current value */ | ||
| 295 | w3b_current_size = tf_read_reg32( | ||
| 296 | &comm->l1_buffer->w3b_size_current_s); | ||
| 297 | if (comm->w3b_shmem_size > w3b_current_size) | ||
| 298 | return 0; | ||
| 299 | |||
| 300 | tf_free_w3b(comm); | ||
| 301 | goto retry; | ||
| 302 | } else { | ||
| 303 | return 0; | ||
| 304 | } | ||
| 305 | } | ||
| 306 | |||
| 307 | /* check H bit */ | ||
| 308 | if ((config_flag_s & (1<<4)) != 0) | ||
| 309 | /* The size of the W3B may change after SMC_INIT */ | ||
| 310 | /* Read the current value */ | ||
| 311 | comm->w3b_shmem_size = tf_read_reg32( | ||
| 312 | &comm->l1_buffer->w3b_size_current_s); | ||
| 313 | else | ||
| 314 | comm->w3b_shmem_size = tf_read_reg32( | ||
| 315 | &comm->l1_buffer->w3b_size_max_s); | ||
| 316 | |||
| 317 | comm->w3b = (u32) internal_vmalloc(comm->w3b_shmem_size); | ||
| 318 | if (comm->w3b == 0) { | ||
| 319 | printk(KERN_ERR "tf_allocate_w3b():" | ||
| 320 | " Out of memory for W3B buffer (%u bytes)!\n", | ||
| 321 | (unsigned int)(comm->w3b_shmem_size)); | ||
| 322 | error = -ENOMEM; | ||
| 323 | goto error; | ||
| 324 | } | ||
| 325 | |||
| 326 | /* initialize the w3b_shmem_desc structure */ | ||
| 327 | comm->w3b_shmem_desc.type = TF_SHMEM_TYPE_PM_HIBERNATE; | ||
| 328 | INIT_LIST_HEAD(&(comm->w3b_shmem_desc.list)); | ||
| 329 | |||
| 330 | flags = (TF_SHMEM_TYPE_READ | TF_SHMEM_TYPE_WRITE); | ||
| 331 | |||
| 332 | /* directly point to the L1 shared buffer W3B descriptors */ | ||
| 333 | w3b_descriptors = comm->l1_buffer->w3b_descriptors; | ||
| 334 | |||
| 335 | /* | ||
| 336 | * tf_fill_descriptor_table uses the following parameter as an | ||
| 337 | * IN/OUT | ||
| 338 | */ | ||
| 339 | |||
| 340 | error = tf_fill_descriptor_table( | ||
| 341 | &(comm->w3b_cpt_alloc_context), | ||
| 342 | &(comm->w3b_shmem_desc), | ||
| 343 | comm->w3b, | ||
| 344 | NULL, | ||
| 345 | w3b_descriptors, | ||
| 346 | comm->w3b_shmem_size, | ||
| 347 | &(comm->w3b_shmem_offset), | ||
| 348 | false, | ||
| 349 | flags, | ||
| 350 | &w3b_descriptor_count); | ||
| 351 | if (error != 0) { | ||
| 352 | printk(KERN_ERR "tf_allocate_w3b():" | ||
| 353 | " tf_fill_descriptor_table failed with " | ||
| 354 | "error code 0x%08x!\n", | ||
| 355 | error); | ||
| 356 | goto error; | ||
| 357 | } | ||
| 358 | |||
| 359 | set_bit(TF_COMM_FLAG_W3B_ALLOCATED, &(comm->flags)); | ||
| 360 | |||
| 361 | /* successful completion */ | ||
| 362 | return 0; | ||
| 363 | |||
| 364 | error: | ||
| 365 | tf_free_w3b(comm); | ||
| 366 | |||
| 367 | return error; | ||
| 368 | } | ||
| 369 | |||
| 370 | /* | ||
| 371 | * Perform a Secure World shutdown operation. | ||
| 372 | * The routine does not return if the operation succeeds. | ||
| 373 | * the routine returns an appropriate error code if | ||
| 374 | * the operation fails. | ||
| 375 | */ | ||
| 376 | int tf_pm_shutdown(struct tf_comm *comm) | ||
| 377 | { | ||
| 378 | #ifdef CONFIG_TFN | ||
| 379 | /* this function is useless for the TEGRA product */ | ||
| 380 | return 0; | ||
| 381 | #else | ||
| 382 | int error; | ||
| 383 | union tf_command command; | ||
| 384 | union tf_answer answer; | ||
| 385 | |||
| 386 | dprintk(KERN_INFO "tf_pm_shutdown()\n"); | ||
| 387 | |||
| 388 | memset(&command, 0, sizeof(command)); | ||
| 389 | |||
| 390 | command.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT; | ||
| 391 | command.header.message_size = | ||
| 392 | (sizeof(struct tf_command_management) - | ||
| 393 | sizeof(struct tf_command_header))/sizeof(u32); | ||
| 394 | |||
| 395 | command.management.command = TF_MANAGEMENT_SHUTDOWN; | ||
| 396 | |||
| 397 | error = tf_send_receive( | ||
| 398 | comm, | ||
| 399 | &command, | ||
| 400 | &answer, | ||
| 401 | NULL, | ||
| 402 | false); | ||
| 403 | |||
| 404 | if (error != 0) { | ||
| 405 | dprintk(KERN_ERR "tf_pm_shutdown(): " | ||
| 406 | "tf_send_receive failed (error %d)!\n", | ||
| 407 | error); | ||
| 408 | return error; | ||
| 409 | } | ||
| 410 | |||
| 411 | #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT | ||
| 412 | if (answer.header.error_code != 0) | ||
| 413 | dprintk(KERN_ERR "tf_driver: shutdown failed.\n"); | ||
| 414 | else | ||
| 415 | dprintk(KERN_INFO "tf_driver: shutdown succeeded.\n"); | ||
| 416 | #endif | ||
| 417 | |||
| 418 | return answer.header.error_code; | ||
| 419 | #endif | ||
| 420 | } | ||
| 421 | |||
| 422 | |||
| 423 | /* | ||
| 424 | * Perform a Secure World hibernate operation. | ||
| 425 | * The routine does not return if the operation succeeds. | ||
| 426 | * the routine returns an appropriate error code if | ||
| 427 | * the operation fails. | ||
| 428 | */ | ||
| 429 | int tf_pm_hibernate(struct tf_comm *comm) | ||
| 430 | { | ||
| 431 | #ifdef CONFIG_TFN | ||
| 432 | /* this function is useless for the TEGRA product */ | ||
| 433 | return 0; | ||
| 434 | #else | ||
| 435 | int error; | ||
| 436 | union tf_command command; | ||
| 437 | union tf_answer answer; | ||
| 438 | u32 first_command; | ||
| 439 | u32 first_free_command; | ||
| 440 | |||
| 441 | dprintk(KERN_INFO "tf_pm_hibernate()\n"); | ||
| 442 | |||
| 443 | error = tf_allocate_w3b(comm); | ||
| 444 | if (error != 0) { | ||
| 445 | dprintk(KERN_ERR "tf_pm_hibernate(): " | ||
| 446 | "tf_allocate_w3b failed (error %d)!\n", | ||
| 447 | error); | ||
| 448 | return error; | ||
| 449 | } | ||
| 450 | |||
| 451 | /* | ||
| 452 | * As the polling thread is already hibernating, we | ||
| 453 | * should send the message and receive the answer ourself | ||
| 454 | */ | ||
| 455 | |||
| 456 | /* build the "prepare to hibernate" message */ | ||
| 457 | command.header.message_type = TF_MESSAGE_TYPE_MANAGEMENT; | ||
| 458 | command.management.command = TF_MANAGEMENT_HIBERNATE; | ||
| 459 | /* Long Form Command */ | ||
| 460 | command.management.shared_mem_descriptors[0] = 0; | ||
| 461 | command.management.shared_mem_descriptors[1] = 0; | ||
| 462 | command.management.w3b_size = | ||
| 463 | comm->w3b_shmem_size | 0x80000000; | ||
| 464 | command.management.w3b_start_offset = | ||
| 465 | comm->w3b_shmem_offset; | ||
| 466 | command.header.operation_id = (u32) &answer; | ||
| 467 | |||
| 468 | tf_dump_command(&command); | ||
| 469 | |||
| 470 | /* find a slot to send the message in */ | ||
| 471 | |||
| 472 | /* AFY: why not use the function tf_send_receive?? We are | ||
| 473 | * duplicating a lot of subtle code here. And it's not going to be | ||
| 474 | * tested because power management is currently not supported by the | ||
| 475 | * secure world. */ | ||
| 476 | for (;;) { | ||
| 477 | int queue_words_count, command_size; | ||
| 478 | |||
| 479 | spin_lock(&(comm->lock)); | ||
| 480 | |||
| 481 | first_command = tf_read_reg32( | ||
| 482 | &comm->l1_buffer->first_command); | ||
| 483 | first_free_command = tf_read_reg32( | ||
| 484 | &comm->l1_buffer->first_free_command); | ||
| 485 | |||
| 486 | queue_words_count = first_free_command - first_command; | ||
| 487 | command_size = command.header.message_size | ||
| 488 | + sizeof(struct tf_command_header); | ||
| 489 | if ((queue_words_count + command_size) < | ||
| 490 | TF_N_MESSAGE_QUEUE_CAPACITY) { | ||
| 491 | /* Command queue is not full */ | ||
| 492 | memcpy(&comm->l1_buffer->command_queue[ | ||
| 493 | first_free_command % | ||
| 494 | TF_N_MESSAGE_QUEUE_CAPACITY], | ||
| 495 | &command, | ||
| 496 | command_size * sizeof(u32)); | ||
| 497 | |||
| 498 | tf_write_reg32(&comm->l1_buffer->first_free_command, | ||
| 499 | first_free_command + command_size); | ||
| 500 | |||
| 501 | spin_unlock(&(comm->lock)); | ||
| 502 | break; | ||
| 503 | } | ||
| 504 | |||
| 505 | spin_unlock(&(comm->lock)); | ||
| 506 | (void)tf_schedule_secure_world(comm); | ||
| 507 | } | ||
| 508 | |||
| 509 | /* now wait for the answer, dispatching other answers */ | ||
| 510 | while (1) { | ||
| 511 | u32 first_answer; | ||
| 512 | u32 first_free_answer; | ||
| 513 | |||
| 514 | /* check all the answers */ | ||
| 515 | first_free_answer = tf_read_reg32( | ||
| 516 | &comm->l1_buffer->first_free_answer); | ||
| 517 | first_answer = tf_read_reg32( | ||
| 518 | &comm->l1_buffer->first_answer); | ||
| 519 | |||
| 520 | if (first_answer != first_free_answer) { | ||
| 521 | int bFoundAnswer = 0; | ||
| 522 | |||
| 523 | do { | ||
| 524 | /* answer queue not empty */ | ||
| 525 | union tf_answer tmp_answer; | ||
| 526 | struct tf_answer_header header; | ||
| 527 | /* size of the command in words of 32bit */ | ||
| 528 | int command_size; | ||
| 529 | |||
| 530 | /* get the message_size */ | ||
| 531 | memcpy(&header, | ||
| 532 | &comm->l1_buffer->answer_queue[ | ||
| 533 | first_answer % | ||
| 534 | TF_S_ANSWER_QUEUE_CAPACITY], | ||
| 535 | sizeof(struct tf_answer_header)); | ||
| 536 | command_size = header.message_size + | ||
| 537 | sizeof(struct tf_answer_header); | ||
| 538 | |||
| 539 | /* | ||
| 540 | * NOTE: message_size is the number of words | ||
| 541 | * following the first word | ||
| 542 | */ | ||
| 543 | memcpy(&tmp_answer, | ||
| 544 | &comm->l1_buffer->answer_queue[ | ||
| 545 | first_answer % | ||
| 546 | TF_S_ANSWER_QUEUE_CAPACITY], | ||
| 547 | command_size * sizeof(u32)); | ||
| 548 | |||
| 549 | tf_dump_answer(&tmp_answer); | ||
| 550 | |||
| 551 | if (tmp_answer.header.operation_id == | ||
| 552 | (u32) &answer) { | ||
| 553 | /* | ||
| 554 | * this is the answer to the "prepare to | ||
| 555 | * hibernate" message | ||
| 556 | */ | ||
| 557 | memcpy(&answer, | ||
| 558 | &tmp_answer, | ||
| 559 | command_size * sizeof(u32)); | ||
| 560 | |||
| 561 | bFoundAnswer = 1; | ||
| 562 | tf_write_reg32( | ||
| 563 | &comm->l1_buffer->first_answer, | ||
| 564 | first_answer + command_size); | ||
| 565 | break; | ||
| 566 | } else { | ||
| 567 | /* | ||
| 568 | * this is a standard message answer, | ||
| 569 | * dispatch it | ||
| 570 | */ | ||
| 571 | struct tf_answer_struct | ||
| 572 | *answerStructure; | ||
| 573 | |||
| 574 | answerStructure = | ||
| 575 | (struct tf_answer_struct *) | ||
| 576 | tmp_answer.header.operation_id; | ||
| 577 | |||
| 578 | memcpy(answerStructure->answer, | ||
| 579 | &tmp_answer, | ||
| 580 | command_size * sizeof(u32)); | ||
| 581 | |||
| 582 | answerStructure->answer_copied = true; | ||
| 583 | } | ||
| 584 | |||
| 585 | tf_write_reg32( | ||
| 586 | &comm->l1_buffer->first_answer, | ||
| 587 | first_answer + command_size); | ||
| 588 | } while (first_answer != first_free_answer); | ||
| 589 | |||
| 590 | if (bFoundAnswer) | ||
| 591 | break; | ||
| 592 | } | ||
| 593 | |||
| 594 | /* | ||
| 595 | * since the Secure World is at least running the "prepare to | ||
| 596 | * hibernate" message, its timeout must be immediate So there is | ||
| 597 | * no need to check its timeout and schedule() the current | ||
| 598 | * thread | ||
| 599 | */ | ||
| 600 | (void)tf_schedule_secure_world(comm); | ||
| 601 | } /* while (1) */ | ||
| 602 | |||
| 603 | printk(KERN_INFO "tf_driver: hibernate.\n"); | ||
| 604 | return 0; | ||
| 605 | #endif | ||
| 606 | } | ||
| 607 | |||
| 608 | |||
| 609 | /* | ||
| 610 | * Perform a Secure World resume operation. | ||
| 611 | * The routine returns once the Secure World is active again | ||
| 612 | * or if an error occurs during the "resume" process | ||
| 613 | */ | ||
| 614 | int tf_pm_resume(struct tf_comm *comm) | ||
| 615 | { | ||
| 616 | #ifdef CONFIG_TFN | ||
| 617 | /* this function is useless for the TEGRA product */ | ||
| 618 | return 0; | ||
| 619 | #else | ||
| 620 | int error; | ||
| 621 | u32 status; | ||
| 622 | |||
| 623 | dprintk(KERN_INFO "tf_pm_resume()\n"); | ||
| 624 | |||
| 625 | error = tf_smc_wake_up( | ||
| 626 | tf_get_l2init_descriptor((u32)comm->l1_buffer), | ||
| 627 | comm->w3b_shmem_offset, | ||
| 628 | comm->w3b_shmem_size); | ||
| 629 | |||
| 630 | if (error != 0) { | ||
| 631 | dprintk(KERN_ERR "tf_pm_resume(): " | ||
| 632 | "tf_smc_wake_up failed (error %d)!\n", | ||
| 633 | error); | ||
| 634 | return error; | ||
| 635 | } | ||
| 636 | |||
| 637 | status = ((tf_read_reg32(&(comm->l1_buffer->status_s)) | ||
| 638 | & TF_STATUS_POWER_STATE_MASK) | ||
| 639 | >> TF_STATUS_POWER_STATE_SHIFT); | ||
| 640 | |||
| 641 | while ((status != TF_POWER_MODE_ACTIVE) | ||
| 642 | && (status != TF_POWER_MODE_PANIC)) { | ||
| 643 | tf_smc_nyield(); | ||
| 644 | |||
| 645 | status = ((tf_read_reg32(&(comm->l1_buffer->status_s)) | ||
| 646 | & TF_STATUS_POWER_STATE_MASK) | ||
| 647 | >> TF_STATUS_POWER_STATE_SHIFT); | ||
| 648 | |||
| 649 | /* | ||
| 650 | * As this may last quite a while, call the kernel scheduler to | ||
| 651 | * hand over CPU for other operations | ||
| 652 | */ | ||
| 653 | schedule(); | ||
| 654 | } | ||
| 655 | |||
| 656 | switch (status) { | ||
| 657 | case TF_POWER_MODE_ACTIVE: | ||
| 658 | break; | ||
| 659 | |||
| 660 | case TF_POWER_MODE_PANIC: | ||
| 661 | dprintk(KERN_ERR "tf_pm_resume(): " | ||
| 662 | "Secure World POWER_MODE_PANIC!\n"); | ||
| 663 | return -EINVAL; | ||
| 664 | |||
| 665 | default: | ||
| 666 | dprintk(KERN_ERR "tf_pm_resume(): " | ||
| 667 | "unexpected Secure World POWER_MODE (%d)!\n", status); | ||
| 668 | return -EINVAL; | ||
| 669 | } | ||
| 670 | |||
| 671 | dprintk(KERN_INFO "tf_pm_resume() succeeded\n"); | ||
| 672 | return 0; | ||
| 673 | #endif | ||
| 674 | } | ||
| 675 | |||
| 676 | /*---------------------------------------------------------------------------- | ||
| 677 | * Communication initialization and termination | ||
| 678 | *----------------------------------------------------------------------------*/ | ||
| 679 | |||
| 680 | /* | ||
| 681 | * Handles the software interrupts issued by the Secure World. | ||
| 682 | */ | ||
| 683 | static irqreturn_t tf_soft_int_handler(int irq, void *dev_id) | ||
| 684 | { | ||
| 685 | struct tf_comm *comm = (struct tf_comm *) dev_id; | ||
| 686 | |||
| 687 | if (comm->l1_buffer == NULL) | ||
| 688 | return IRQ_NONE; | ||
| 689 | |||
| 690 | if ((tf_read_reg32(&comm->l1_buffer->status_s) & | ||
| 691 | TF_STATUS_P_MASK) == 0) | ||
| 692 | /* interrupt not issued by the Trusted Foundations Software */ | ||
| 693 | return IRQ_NONE; | ||
| 694 | |||
| 695 | tf_smc_reset_irq(); | ||
| 696 | |||
| 697 | /* signal N_SM_EVENT */ | ||
| 698 | wake_up(&comm->wait_queue); | ||
| 699 | |||
| 700 | return IRQ_HANDLED; | ||
| 701 | } | ||
| 702 | |||
| 703 | /* | ||
| 704 | * Initializes the communication with the Secure World. | ||
| 705 | * The L1 shared buffer is allocated and the Secure World | ||
| 706 | * is yielded for the first time. | ||
| 707 | * returns successfuly once the communication with | ||
| 708 | * the Secure World is up and running | ||
| 709 | * | ||
| 710 | * Returns 0 upon success or appropriate error code | ||
| 711 | * upon failure | ||
| 712 | */ | ||
| 713 | int tf_init(struct tf_comm *comm) | ||
| 714 | { | ||
| 715 | int error; | ||
| 716 | struct page *buffer_page; | ||
| 717 | u32 protocol_version; | ||
| 718 | |||
| 719 | dprintk(KERN_INFO "tf_init()\n"); | ||
| 720 | |||
| 721 | spin_lock_init(&(comm->lock)); | ||
| 722 | comm->flags = 0; | ||
| 723 | comm->l1_buffer = NULL; | ||
| 724 | init_waitqueue_head(&(comm->wait_queue)); | ||
| 725 | |||
| 726 | /* | ||
| 727 | * Check the Secure World protocol version is the expected one. | ||
| 728 | */ | ||
| 729 | tf_smc_get_protocol_version(&protocol_version); | ||
| 730 | |||
| 731 | if ((GET_PROTOCOL_MAJOR_VERSION(protocol_version)) | ||
| 732 | != TF_S_PROTOCOL_MAJOR_VERSION) { | ||
| 733 | printk(KERN_ERR "tf_init():" | ||
| 734 | " Unsupported Secure World Major Version " | ||
| 735 | "(0x%02X, expected 0x%02X)!\n", | ||
| 736 | GET_PROTOCOL_MAJOR_VERSION(protocol_version), | ||
| 737 | TF_S_PROTOCOL_MAJOR_VERSION); | ||
| 738 | error = -EIO; | ||
| 739 | goto error; | ||
| 740 | } | ||
| 741 | |||
| 742 | /* | ||
| 743 | * Register the software interrupt handler if required to. | ||
| 744 | */ | ||
| 745 | if (comm->soft_int_irq != -1) { | ||
| 746 | dprintk(KERN_INFO "tf_init(): " | ||
| 747 | "Registering software interrupt handler (IRQ %d)\n", | ||
| 748 | comm->soft_int_irq); | ||
| 749 | |||
| 750 | error = request_irq(comm->soft_int_irq, | ||
| 751 | tf_soft_int_handler, | ||
| 752 | IRQF_SHARED, | ||
| 753 | TF_DEVICE_BASE_NAME, | ||
| 754 | comm); | ||
| 755 | if (error != 0) { | ||
| 756 | dprintk(KERN_ERR "tf_init(): " | ||
| 757 | "request_irq failed for irq %d (error %d)\n", | ||
| 758 | comm->soft_int_irq, error); | ||
| 759 | goto error; | ||
| 760 | } | ||
| 761 | set_bit(TF_COMM_FLAG_IRQ_REQUESTED, &(comm->flags)); | ||
| 762 | } | ||
| 763 | |||
| 764 | /* | ||
| 765 | * Allocate and initialize the L1 shared buffer. | ||
| 766 | */ | ||
| 767 | comm->l1_buffer = (void *) internal_get_zeroed_page(GFP_KERNEL); | ||
| 768 | if (comm->l1_buffer == NULL) { | ||
| 769 | printk(KERN_ERR "tf_init():" | ||
| 770 | " get_zeroed_page failed for L1 shared buffer!\n"); | ||
| 771 | error = -ENOMEM; | ||
| 772 | goto error; | ||
| 773 | } | ||
| 774 | |||
| 775 | /* | ||
| 776 | * Ensure the page storing the L1 shared buffer is mapped. | ||
| 777 | */ | ||
| 778 | buffer_page = virt_to_page(comm->l1_buffer); | ||
| 779 | trylock_page(buffer_page); | ||
| 780 | |||
| 781 | dprintk(KERN_INFO "tf_init(): " | ||
| 782 | "L1 shared buffer allocated at virtual:%p, " | ||
| 783 | "physical:%p (page:%p)\n", | ||
| 784 | comm->l1_buffer, | ||
| 785 | (void *)virt_to_phys(comm->l1_buffer), | ||
| 786 | buffer_page); | ||
| 787 | |||
| 788 | set_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED, &(comm->flags)); | ||
| 789 | |||
| 790 | /* | ||
| 791 | * Init SMC | ||
| 792 | */ | ||
| 793 | error = tf_smc_init( | ||
| 794 | tf_get_l2init_descriptor((u32)comm->l1_buffer)); | ||
| 795 | if (error != S_SUCCESS) { | ||
| 796 | dprintk(KERN_ERR "tf_init(): " | ||
| 797 | "tf_smc_init failed (error 0x%08X)!\n", | ||
| 798 | error); | ||
| 799 | goto error; | ||
| 800 | } | ||
| 801 | |||
| 802 | /* | ||
| 803 | * check whether the interrupts are actually enabled | ||
| 804 | * If not, remove irq handler | ||
| 805 | */ | ||
| 806 | if ((tf_read_reg32(&comm->l1_buffer->config_flag_s) & | ||
| 807 | TF_CONFIG_FLAG_S) == 0) { | ||
| 808 | if (test_and_clear_bit(TF_COMM_FLAG_IRQ_REQUESTED, | ||
| 809 | &(comm->flags)) != 0) { | ||
| 810 | dprintk(KERN_INFO "tf_init(): " | ||
| 811 | "Interrupts not used, unregistering " | ||
| 812 | "softint (IRQ %d)\n", | ||
| 813 | comm->soft_int_irq); | ||
| 814 | |||
| 815 | free_irq(comm->soft_int_irq, comm); | ||
| 816 | } | ||
| 817 | } else { | ||
| 818 | if (test_bit(TF_COMM_FLAG_IRQ_REQUESTED, | ||
| 819 | &(comm->flags)) == 0) { | ||
| 820 | /* | ||
| 821 | * Interrupts are enabled in the Secure World, but not | ||
| 822 | * handled by driver | ||
| 823 | */ | ||
| 824 | dprintk(KERN_ERR "tf_init(): " | ||
| 825 | "soft_interrupt argument not provided\n"); | ||
| 826 | error = -EINVAL; | ||
| 827 | goto error; | ||
| 828 | } | ||
| 829 | } | ||
| 830 | |||
| 831 | /* | ||
| 832 | * Successful completion. | ||
| 833 | */ | ||
| 834 | |||
| 835 | /* yield for the first time */ | ||
| 836 | (void)tf_schedule_secure_world(comm); | ||
| 837 | |||
| 838 | dprintk(KERN_INFO "tf_init(): Success\n"); | ||
| 839 | return S_SUCCESS; | ||
| 840 | |||
| 841 | error: | ||
| 842 | /* | ||
| 843 | * Error handling. | ||
| 844 | */ | ||
| 845 | dprintk(KERN_INFO "tf_init(): Failure (error %d)\n", | ||
| 846 | error); | ||
| 847 | tf_terminate(comm); | ||
| 848 | return error; | ||
| 849 | } | ||
| 850 | |||
| 851 | |||
| 852 | /* | ||
| 853 | * Attempt to terminate the communication with the Secure World. | ||
| 854 | * The L1 shared buffer is freed. | ||
| 855 | * Calling this routine terminates definitaly the communication | ||
| 856 | * with the Secure World : there is no way to inform the Secure World of a new | ||
| 857 | * L1 shared buffer to be used once it has been initialized. | ||
| 858 | */ | ||
| 859 | void tf_terminate(struct tf_comm *comm) | ||
| 860 | { | ||
| 861 | dprintk(KERN_INFO "tf_terminate()\n"); | ||
| 862 | |||
| 863 | set_bit(TF_COMM_FLAG_TERMINATING, &(comm->flags)); | ||
| 864 | |||
| 865 | if ((test_bit(TF_COMM_FLAG_W3B_ALLOCATED, | ||
| 866 | &(comm->flags))) != 0) { | ||
| 867 | dprintk(KERN_INFO "tf_terminate(): " | ||
| 868 | "Freeing the W3B buffer...\n"); | ||
| 869 | tf_free_w3b(comm); | ||
| 870 | } | ||
| 871 | |||
| 872 | if ((test_bit(TF_COMM_FLAG_L1_SHARED_ALLOCATED, | ||
| 873 | &(comm->flags))) != 0) { | ||
| 874 | __clear_page_locked(virt_to_page(comm->l1_buffer)); | ||
| 875 | internal_free_page((unsigned long) comm->l1_buffer); | ||
| 876 | } | ||
| 877 | |||
| 878 | if ((test_bit(TF_COMM_FLAG_IRQ_REQUESTED, | ||
| 879 | &(comm->flags))) != 0) { | ||
| 880 | dprintk(KERN_INFO "tf_terminate(): " | ||
| 881 | "Unregistering softint (IRQ %d)\n", | ||
| 882 | comm->soft_int_irq); | ||
| 883 | free_irq(comm->soft_int_irq, comm); | ||
| 884 | } | ||
| 885 | } | ||
diff --git a/security/tf_driver/tf_conn.c b/security/tf_driver/tf_conn.c new file mode 100644 index 00000000000..3148fec4635 --- /dev/null +++ b/security/tf_driver/tf_conn.c | |||
| @@ -0,0 +1,1574 @@ | |||
| 1 | /** | ||
| 2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 17 | * MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/atomic.h> | ||
| 21 | #include <linux/uaccess.h> | ||
| 22 | #include <linux/delay.h> | ||
| 23 | #include <linux/errno.h> | ||
| 24 | #include <linux/list.h> | ||
| 25 | #include <linux/mm.h> | ||
| 26 | #include <linux/pagemap.h> | ||
| 27 | #include <linux/stddef.h> | ||
| 28 | #include <linux/types.h> | ||
| 29 | |||
| 30 | #include "s_version.h" | ||
| 31 | |||
| 32 | #include "tf_protocol.h" | ||
| 33 | #include "tf_defs.h" | ||
| 34 | #include "tf_util.h" | ||
| 35 | #include "tf_comm.h" | ||
| 36 | #include "tf_conn.h" | ||
| 37 | |||
| 38 | #ifdef CONFIG_TF_ZEBRA | ||
| 39 | #include "tf_crypto.h" | ||
| 40 | #endif | ||
| 41 | |||
| 42 | #ifdef CONFIG_ANDROID | ||
| 43 | #define TF_PRIVILEGED_UID_GID 1000 /* Android system AID */ | ||
| 44 | #else | ||
| 45 | #define TF_PRIVILEGED_UID_GID 0 | ||
| 46 | #endif | ||
| 47 | |||
| 48 | /*---------------------------------------------------------------------------- | ||
| 49 | * Management of the shared memory blocks. | ||
| 50 | * | ||
| 51 | * Shared memory blocks are the blocks registered through | ||
| 52 | * the commands REGISTER_SHARED_MEMORY and POWER_MANAGEMENT | ||
| 53 | *----------------------------------------------------------------------------*/ | ||
| 54 | |||
| 55 | /** | ||
| 56 | * Unmaps a shared memory | ||
| 57 | **/ | ||
| 58 | void tf_unmap_shmem( | ||
| 59 | struct tf_connection *connection, | ||
| 60 | struct tf_shmem_desc *shmem_desc, | ||
| 61 | u32 full_cleanup) | ||
| 62 | { | ||
| 63 | /* check shmem_desc contains a descriptor */ | ||
| 64 | if (shmem_desc == NULL) | ||
| 65 | return; | ||
| 66 | |||
| 67 | dprintk(KERN_DEBUG "tf_unmap_shmem(%p)\n", shmem_desc); | ||
| 68 | |||
| 69 | retry: | ||
| 70 | mutex_lock(&(connection->shmem_mutex)); | ||
| 71 | if (atomic_read(&shmem_desc->ref_count) > 1) { | ||
| 72 | /* | ||
| 73 | * Shared mem still in use, wait for other operations completion | ||
| 74 | * before actually unmapping it. | ||
| 75 | */ | ||
| 76 | dprintk(KERN_INFO "Descriptor in use\n"); | ||
| 77 | mutex_unlock(&(connection->shmem_mutex)); | ||
| 78 | schedule(); | ||
| 79 | goto retry; | ||
| 80 | } | ||
| 81 | |||
| 82 | tf_cleanup_shared_memory( | ||
| 83 | &(connection->cpt_alloc_context), | ||
| 84 | shmem_desc, | ||
| 85 | full_cleanup); | ||
| 86 | |||
| 87 | list_del(&(shmem_desc->list)); | ||
| 88 | |||
| 89 | if ((shmem_desc->type == TF_SHMEM_TYPE_REGISTERED_SHMEM) || | ||
| 90 | (full_cleanup != 0)) { | ||
| 91 | internal_kfree(shmem_desc); | ||
| 92 | |||
| 93 | atomic_dec(&(connection->shmem_count)); | ||
| 94 | } else { | ||
| 95 | /* | ||
| 96 | * This is a preallocated shared memory, add to free list | ||
| 97 | * Since the device context is unmapped last, it is | ||
| 98 | * always the first element of the free list if no | ||
| 99 | * device context has been created | ||
| 100 | */ | ||
| 101 | shmem_desc->block_identifier = 0; | ||
| 102 | list_add(&(shmem_desc->list), &(connection->free_shmem_list)); | ||
| 103 | } | ||
| 104 | |||
| 105 | mutex_unlock(&(connection->shmem_mutex)); | ||
| 106 | } | ||
| 107 | |||
| 108 | |||
| 109 | /** | ||
| 110 | * Find the first available slot for a new block of shared memory | ||
| 111 | * and map the user buffer. | ||
| 112 | * Update the descriptors to L1 descriptors | ||
| 113 | * Update the buffer_start_offset and buffer_size fields | ||
| 114 | * shmem_desc is updated to the mapped shared memory descriptor | ||
| 115 | **/ | ||
| 116 | int tf_map_shmem( | ||
| 117 | struct tf_connection *connection, | ||
| 118 | u32 buffer, | ||
| 119 | /* flags for read-write access rights on the memory */ | ||
| 120 | u32 flags, | ||
| 121 | bool in_user_space, | ||
| 122 | u32 descriptors[TF_MAX_COARSE_PAGES], | ||
| 123 | u32 *buffer_start_offset, | ||
| 124 | u32 buffer_size, | ||
| 125 | struct tf_shmem_desc **shmem_desc, | ||
| 126 | u32 *descriptor_count) | ||
| 127 | { | ||
| 128 | struct tf_shmem_desc *desc = NULL; | ||
| 129 | int error; | ||
| 130 | |||
| 131 | dprintk(KERN_INFO "tf_map_shmem(%p, %p, flags = 0x%08x)\n", | ||
| 132 | connection, | ||
| 133 | (void *) buffer, | ||
| 134 | flags); | ||
| 135 | |||
| 136 | mutex_lock(&(connection->shmem_mutex)); | ||
| 137 | |||
| 138 | /* | ||
| 139 | * Check the list of free shared memory | ||
| 140 | * is not empty | ||
| 141 | */ | ||
| 142 | if (list_empty(&(connection->free_shmem_list))) { | ||
| 143 | if (atomic_read(&(connection->shmem_count)) == | ||
| 144 | TF_SHMEM_MAX_COUNT) { | ||
| 145 | printk(KERN_ERR "tf_map_shmem(%p):" | ||
| 146 | " maximum shared memories already registered\n", | ||
| 147 | connection); | ||
| 148 | error = -ENOMEM; | ||
| 149 | goto error; | ||
| 150 | } | ||
| 151 | |||
| 152 | /* no descriptor available, allocate a new one */ | ||
| 153 | |||
| 154 | desc = (struct tf_shmem_desc *) internal_kmalloc( | ||
| 155 | sizeof(*desc), GFP_KERNEL); | ||
| 156 | if (desc == NULL) { | ||
| 157 | printk(KERN_ERR "tf_map_shmem(%p):" | ||
| 158 | " failed to allocate descriptor\n", | ||
| 159 | connection); | ||
| 160 | error = -ENOMEM; | ||
| 161 | goto error; | ||
| 162 | } | ||
| 163 | |||
| 164 | /* Initialize the structure */ | ||
| 165 | desc->type = TF_SHMEM_TYPE_REGISTERED_SHMEM; | ||
| 166 | atomic_set(&desc->ref_count, 1); | ||
| 167 | INIT_LIST_HEAD(&(desc->list)); | ||
| 168 | |||
| 169 | atomic_inc(&(connection->shmem_count)); | ||
| 170 | } else { | ||
| 171 | /* take the first free shared memory descriptor */ | ||
| 172 | desc = list_first_entry(&(connection->free_shmem_list), | ||
| 173 | struct tf_shmem_desc, list); | ||
| 174 | list_del(&(desc->list)); | ||
| 175 | } | ||
| 176 | |||
| 177 | /* Add the descriptor to the used list */ | ||
| 178 | list_add(&(desc->list), &(connection->used_shmem_list)); | ||
| 179 | |||
| 180 | error = tf_fill_descriptor_table( | ||
| 181 | &(connection->cpt_alloc_context), | ||
| 182 | desc, | ||
| 183 | buffer, | ||
| 184 | connection->vmas, | ||
| 185 | descriptors, | ||
| 186 | buffer_size, | ||
| 187 | buffer_start_offset, | ||
| 188 | in_user_space, | ||
| 189 | flags, | ||
| 190 | descriptor_count); | ||
| 191 | |||
| 192 | if (error != 0) { | ||
| 193 | dprintk(KERN_ERR "tf_map_shmem(%p):" | ||
| 194 | " tf_fill_descriptor_table failed with error " | ||
| 195 | "code %d!\n", | ||
| 196 | connection, | ||
| 197 | error); | ||
| 198 | goto error; | ||
| 199 | } | ||
| 200 | desc->client_buffer = (u8 *) buffer; | ||
| 201 | |||
| 202 | /* | ||
| 203 | * Successful completion. | ||
| 204 | */ | ||
| 205 | *shmem_desc = desc; | ||
| 206 | mutex_unlock(&(connection->shmem_mutex)); | ||
| 207 | dprintk(KERN_DEBUG "tf_map_shmem: success\n"); | ||
| 208 | return 0; | ||
| 209 | |||
| 210 | |||
| 211 | /* | ||
| 212 | * Error handling. | ||
| 213 | */ | ||
| 214 | error: | ||
| 215 | mutex_unlock(&(connection->shmem_mutex)); | ||
| 216 | dprintk(KERN_ERR "tf_map_shmem: failure with error code %d\n", | ||
| 217 | error); | ||
| 218 | |||
| 219 | tf_unmap_shmem( | ||
| 220 | connection, | ||
| 221 | desc, | ||
| 222 | 0); | ||
| 223 | |||
| 224 | return error; | ||
| 225 | } | ||
| 226 | |||
| 227 | |||
| 228 | |||
| 229 | /* This function is a copy of the find_vma() function | ||
| 230 | in linux kernel 2.6.15 version with some fixes : | ||
| 231 | - memory block may end on vm_end | ||
| 232 | - check the full memory block is in the memory area | ||
| 233 | - guarantee NULL is returned if no memory area is found */ | ||
| 234 | struct vm_area_struct *tf_find_vma(struct mm_struct *mm, | ||
| 235 | unsigned long addr, unsigned long size) | ||
| 236 | { | ||
| 237 | struct vm_area_struct *vma = NULL; | ||
| 238 | |||
| 239 | dprintk(KERN_INFO | ||
| 240 | "tf_find_vma addr=0x%lX size=0x%lX\n", addr, size); | ||
| 241 | |||
| 242 | if (mm) { | ||
| 243 | /* Check the cache first. */ | ||
| 244 | /* (Cache hit rate is typically around 35%.) */ | ||
| 245 | vma = mm->mmap_cache; | ||
| 246 | if (!(vma && vma->vm_end >= (addr+size) && | ||
| 247 | vma->vm_start <= addr)) { | ||
| 248 | struct rb_node *rb_node; | ||
| 249 | |||
| 250 | rb_node = mm->mm_rb.rb_node; | ||
| 251 | vma = NULL; | ||
| 252 | |||
| 253 | while (rb_node) { | ||
| 254 | struct vm_area_struct *vma_tmp; | ||
| 255 | |||
| 256 | vma_tmp = rb_entry(rb_node, | ||
| 257 | struct vm_area_struct, vm_rb); | ||
| 258 | |||
| 259 | dprintk(KERN_INFO | ||
| 260 | "vma_tmp->vm_start=0x%lX" | ||
| 261 | "vma_tmp->vm_end=0x%lX\n", | ||
| 262 | vma_tmp->vm_start, | ||
| 263 | vma_tmp->vm_end); | ||
| 264 | |||
| 265 | if (vma_tmp->vm_end >= (addr+size)) { | ||
| 266 | vma = vma_tmp; | ||
| 267 | if (vma_tmp->vm_start <= addr) | ||
| 268 | break; | ||
| 269 | |||
| 270 | rb_node = rb_node->rb_left; | ||
| 271 | } else { | ||
| 272 | rb_node = rb_node->rb_right; | ||
| 273 | } | ||
| 274 | } | ||
| 275 | |||
| 276 | if (vma) | ||
| 277 | mm->mmap_cache = vma; | ||
| 278 | if (rb_node == NULL) | ||
| 279 | vma = NULL; | ||
| 280 | } | ||
| 281 | } | ||
| 282 | return vma; | ||
| 283 | } | ||
| 284 | |||
| 285 | int tf_validate_shmem_and_flags( | ||
| 286 | u32 shmem, | ||
| 287 | u32 shmem_size, | ||
| 288 | u32 flags) | ||
| 289 | { | ||
| 290 | struct vm_area_struct *vma; | ||
| 291 | u32 chunk; | ||
| 292 | |||
| 293 | if (shmem_size == 0) | ||
| 294 | /* This is always valid */ | ||
| 295 | return 0; | ||
| 296 | |||
| 297 | if ((shmem + shmem_size) < shmem) | ||
| 298 | /* Overflow */ | ||
| 299 | return -EINVAL; | ||
| 300 | |||
| 301 | down_read(¤t->mm->mmap_sem); | ||
| 302 | |||
| 303 | /* | ||
| 304 | * When looking for a memory address, split buffer into chunks of | ||
| 305 | * size=PAGE_SIZE. | ||
| 306 | */ | ||
| 307 | chunk = PAGE_SIZE - (shmem & (PAGE_SIZE-1)); | ||
| 308 | if (chunk > shmem_size) | ||
| 309 | chunk = shmem_size; | ||
| 310 | |||
| 311 | do { | ||
| 312 | vma = tf_find_vma(current->mm, shmem, chunk); | ||
| 313 | |||
| 314 | if (vma == NULL) { | ||
| 315 | dprintk(KERN_ERR "%s: area not found\n", __func__); | ||
| 316 | goto error; | ||
| 317 | } | ||
| 318 | |||
| 319 | if (flags & TF_SHMEM_TYPE_READ) | ||
| 320 | if (!(vma->vm_flags & VM_READ)) { | ||
| 321 | dprintk(KERN_ERR "%s: no read permission\n", | ||
| 322 | __func__); | ||
| 323 | goto error; | ||
| 324 | } | ||
| 325 | if (flags & TF_SHMEM_TYPE_WRITE) | ||
| 326 | if (!(vma->vm_flags & VM_WRITE)) { | ||
| 327 | dprintk(KERN_ERR "%s: no write permission\n", | ||
| 328 | __func__); | ||
| 329 | goto error; | ||
| 330 | } | ||
| 331 | |||
| 332 | shmem_size -= chunk; | ||
| 333 | shmem += chunk; | ||
| 334 | chunk = (shmem_size <= PAGE_SIZE ? | ||
| 335 | shmem_size : PAGE_SIZE); | ||
| 336 | } while (shmem_size != 0); | ||
| 337 | |||
| 338 | up_read(¤t->mm->mmap_sem); | ||
| 339 | return 0; | ||
| 340 | |||
| 341 | error: | ||
| 342 | up_read(¤t->mm->mmap_sem); | ||
| 343 | return -EFAULT; | ||
| 344 | } | ||
| 345 | |||
| 346 | |||
| 347 | static int tf_map_temp_shmem(struct tf_connection *connection, | ||
| 348 | struct tf_command_param_temp_memref *temp_memref, | ||
| 349 | u32 param_type, | ||
| 350 | struct tf_shmem_desc **shmem_desc) | ||
| 351 | { | ||
| 352 | u32 flags; | ||
| 353 | u32 error = S_SUCCESS; | ||
| 354 | bool in_user_space = connection->owner != TF_CONNECTION_OWNER_KERNEL; | ||
| 355 | |||
| 356 | dprintk(KERN_INFO "tf_map_temp_shmem(%p, " | ||
| 357 | "0x%08x[size=0x%08x], offset=0x%08x)\n", | ||
| 358 | connection, | ||
| 359 | temp_memref->descriptor, | ||
| 360 | temp_memref->size, | ||
| 361 | temp_memref->offset); | ||
| 362 | |||
| 363 | switch (param_type) { | ||
| 364 | case TF_PARAM_TYPE_MEMREF_TEMP_INPUT: | ||
| 365 | flags = TF_SHMEM_TYPE_READ; | ||
| 366 | break; | ||
| 367 | case TF_PARAM_TYPE_MEMREF_TEMP_OUTPUT: | ||
| 368 | flags = TF_SHMEM_TYPE_WRITE; | ||
| 369 | break; | ||
| 370 | case TF_PARAM_TYPE_MEMREF_TEMP_INOUT: | ||
| 371 | flags = TF_SHMEM_TYPE_WRITE | TF_SHMEM_TYPE_READ; | ||
| 372 | break; | ||
| 373 | default: | ||
| 374 | error = -EINVAL; | ||
| 375 | goto error; | ||
| 376 | } | ||
| 377 | |||
| 378 | if (temp_memref->descriptor == 0) { | ||
| 379 | /* NULL tmpref */ | ||
| 380 | temp_memref->offset = 0; | ||
| 381 | *shmem_desc = NULL; | ||
| 382 | } else if ((temp_memref->descriptor != 0) && | ||
| 383 | (temp_memref->size == 0)) { | ||
| 384 | /* Empty tmpref */ | ||
| 385 | temp_memref->offset = temp_memref->descriptor; | ||
| 386 | temp_memref->descriptor = 0; | ||
| 387 | temp_memref->size = 0; | ||
| 388 | *shmem_desc = NULL; | ||
| 389 | } else { | ||
| 390 | /* Map the temp shmem block */ | ||
| 391 | |||
| 392 | u32 shared_mem_descriptors[TF_MAX_COARSE_PAGES]; | ||
| 393 | u32 descriptor_count; | ||
| 394 | |||
| 395 | if (in_user_space) { | ||
| 396 | error = tf_validate_shmem_and_flags( | ||
| 397 | temp_memref->descriptor, | ||
| 398 | temp_memref->size, | ||
| 399 | flags); | ||
| 400 | if (error != 0) | ||
| 401 | goto error; | ||
| 402 | } | ||
| 403 | |||
| 404 | error = tf_map_shmem( | ||
| 405 | connection, | ||
| 406 | temp_memref->descriptor, | ||
| 407 | flags, | ||
| 408 | in_user_space, | ||
| 409 | shared_mem_descriptors, | ||
| 410 | &(temp_memref->offset), | ||
| 411 | temp_memref->size, | ||
| 412 | shmem_desc, | ||
| 413 | &descriptor_count); | ||
| 414 | temp_memref->descriptor = shared_mem_descriptors[0]; | ||
| 415 | } | ||
| 416 | |||
| 417 | error: | ||
| 418 | return error; | ||
| 419 | } | ||
| 420 | |||
| 421 | /* | ||
| 422 | * Clean up a list of shared memory descriptors. | ||
| 423 | */ | ||
| 424 | static void tf_shared_memory_cleanup_list( | ||
| 425 | struct tf_connection *connection, | ||
| 426 | struct list_head *shmem_desc_list) | ||
| 427 | { | ||
| 428 | while (!list_empty(shmem_desc_list)) { | ||
| 429 | struct tf_shmem_desc *shmem_desc; | ||
| 430 | |||
| 431 | shmem_desc = list_first_entry(shmem_desc_list, | ||
| 432 | struct tf_shmem_desc, list); | ||
| 433 | |||
| 434 | tf_unmap_shmem(connection, shmem_desc, 1); | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | |||
| 439 | /* | ||
| 440 | * Clean up the shared memory information in the connection. | ||
| 441 | * Releases all allocated pages. | ||
| 442 | */ | ||
| 443 | static void tf_cleanup_shared_memories(struct tf_connection *connection) | ||
| 444 | { | ||
| 445 | /* clean up the list of used and free descriptors. | ||
| 446 | * done outside the mutex, because tf_unmap_shmem already | ||
| 447 | * mutex()ed | ||
| 448 | */ | ||
| 449 | tf_shared_memory_cleanup_list(connection, | ||
| 450 | &connection->used_shmem_list); | ||
| 451 | tf_shared_memory_cleanup_list(connection, | ||
| 452 | &connection->free_shmem_list); | ||
| 453 | |||
| 454 | mutex_lock(&(connection->shmem_mutex)); | ||
| 455 | |||
| 456 | /* Free the Vmas page */ | ||
| 457 | if (connection->vmas) { | ||
| 458 | internal_free_page((unsigned long) connection->vmas); | ||
| 459 | connection->vmas = NULL; | ||
| 460 | } | ||
| 461 | |||
| 462 | tf_release_coarse_page_table_allocator( | ||
| 463 | &(connection->cpt_alloc_context)); | ||
| 464 | |||
| 465 | mutex_unlock(&(connection->shmem_mutex)); | ||
| 466 | } | ||
| 467 | |||
| 468 | |||
| 469 | /* | ||
| 470 | * Initialize the shared memory in a connection. | ||
| 471 | * Allocates the minimum memory to be provided | ||
| 472 | * for shared memory management | ||
| 473 | */ | ||
| 474 | int tf_init_shared_memory(struct tf_connection *connection) | ||
| 475 | { | ||
| 476 | int error; | ||
| 477 | int i; | ||
| 478 | int coarse_page_index; | ||
| 479 | |||
| 480 | /* | ||
| 481 | * We only need to initialize special elements and attempt to allocate | ||
| 482 | * the minimum shared memory descriptors we want to support | ||
| 483 | */ | ||
| 484 | |||
| 485 | mutex_init(&(connection->shmem_mutex)); | ||
| 486 | INIT_LIST_HEAD(&(connection->free_shmem_list)); | ||
| 487 | INIT_LIST_HEAD(&(connection->used_shmem_list)); | ||
| 488 | atomic_set(&(connection->shmem_count), 0); | ||
| 489 | |||
| 490 | tf_init_coarse_page_table_allocator( | ||
| 491 | &(connection->cpt_alloc_context)); | ||
| 492 | |||
| 493 | |||
| 494 | /* | ||
| 495 | * Preallocate 3 pages to increase the chances that a connection | ||
| 496 | * succeeds in allocating shared mem | ||
| 497 | */ | ||
| 498 | for (i = 0; | ||
| 499 | i < 3; | ||
| 500 | i++) { | ||
| 501 | struct tf_shmem_desc *shmem_desc = | ||
| 502 | (struct tf_shmem_desc *) internal_kmalloc( | ||
| 503 | sizeof(*shmem_desc), GFP_KERNEL); | ||
| 504 | |||
| 505 | if (shmem_desc == NULL) { | ||
| 506 | printk(KERN_ERR "tf_init_shared_memory(%p):" | ||
| 507 | " failed to pre allocate descriptor %d\n", | ||
| 508 | connection, | ||
| 509 | i); | ||
| 510 | error = -ENOMEM; | ||
| 511 | goto error; | ||
| 512 | } | ||
| 513 | |||
| 514 | for (coarse_page_index = 0; | ||
| 515 | coarse_page_index < TF_MAX_COARSE_PAGES; | ||
| 516 | coarse_page_index++) { | ||
| 517 | struct tf_coarse_page_table *coarse_pg_table; | ||
| 518 | |||
| 519 | coarse_pg_table = tf_alloc_coarse_page_table( | ||
| 520 | &(connection->cpt_alloc_context), | ||
| 521 | TF_PAGE_DESCRIPTOR_TYPE_PREALLOCATED); | ||
| 522 | |||
| 523 | if (coarse_pg_table == NULL) { | ||
| 524 | printk(KERN_ERR "tf_init_shared_memory(%p)" | ||
| 525 | ": descriptor %d coarse page %d - " | ||
| 526 | "tf_alloc_coarse_page_table() " | ||
| 527 | "failed\n", | ||
| 528 | connection, | ||
| 529 | i, | ||
| 530 | coarse_page_index); | ||
| 531 | error = -ENOMEM; | ||
| 532 | goto error; | ||
| 533 | } | ||
| 534 | |||
| 535 | shmem_desc->coarse_pg_table[coarse_page_index] = | ||
| 536 | coarse_pg_table; | ||
| 537 | } | ||
| 538 | shmem_desc->coarse_pg_table_count = 0; | ||
| 539 | |||
| 540 | shmem_desc->type = TF_SHMEM_TYPE_PREALLOC_REGISTERED_SHMEM; | ||
| 541 | atomic_set(&shmem_desc->ref_count, 1); | ||
| 542 | |||
| 543 | /* | ||
| 544 | * add this preallocated descriptor to the list of free | ||
| 545 | * descriptors Keep the device context specific one at the | ||
| 546 | * beginning of the list | ||
| 547 | */ | ||
| 548 | INIT_LIST_HEAD(&(shmem_desc->list)); | ||
| 549 | list_add_tail(&(shmem_desc->list), | ||
| 550 | &(connection->free_shmem_list)); | ||
| 551 | } | ||
| 552 | |||
| 553 | /* allocate memory for the vmas structure */ | ||
| 554 | connection->vmas = | ||
| 555 | (struct vm_area_struct **) internal_get_zeroed_page(GFP_KERNEL); | ||
| 556 | if (connection->vmas == NULL) { | ||
| 557 | printk(KERN_ERR "tf_init_shared_memory(%p):" | ||
| 558 | " vmas - failed to get_zeroed_page\n", | ||
| 559 | connection); | ||
| 560 | error = -ENOMEM; | ||
| 561 | goto error; | ||
| 562 | } | ||
| 563 | |||
| 564 | return 0; | ||
| 565 | |||
| 566 | error: | ||
| 567 | tf_cleanup_shared_memories(connection); | ||
| 568 | return error; | ||
| 569 | } | ||
| 570 | |||
| 571 | /*---------------------------------------------------------------------------- | ||
| 572 | * Connection operations to the Secure World | ||
| 573 | *----------------------------------------------------------------------------*/ | ||
| 574 | |||
| 575 | int tf_create_device_context( | ||
| 576 | struct tf_connection *connection) | ||
| 577 | { | ||
| 578 | union tf_command command; | ||
| 579 | union tf_answer answer; | ||
| 580 | int error = 0; | ||
| 581 | |||
| 582 | dprintk(KERN_INFO "tf_create_device_context(%p)\n", | ||
| 583 | connection); | ||
| 584 | |||
| 585 | command.create_device_context.message_type = | ||
| 586 | TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT; | ||
| 587 | command.create_device_context.message_size = | ||
| 588 | (sizeof(struct tf_command_create_device_context) | ||
| 589 | - sizeof(struct tf_command_header))/sizeof(u32); | ||
| 590 | command.create_device_context.operation_id = (u32) &answer; | ||
| 591 | command.create_device_context.device_context_id = (u32) connection; | ||
| 592 | |||
| 593 | error = tf_send_receive( | ||
| 594 | &connection->dev->sm, | ||
| 595 | &command, | ||
| 596 | &answer, | ||
| 597 | connection, | ||
| 598 | true); | ||
| 599 | |||
| 600 | if ((error != 0) || | ||
| 601 | (answer.create_device_context.error_code != S_SUCCESS)) | ||
| 602 | goto error; | ||
| 603 | |||
| 604 | /* | ||
| 605 | * CREATE_DEVICE_CONTEXT succeeded, | ||
| 606 | * store device context handler and update connection status | ||
| 607 | */ | ||
| 608 | connection->device_context = | ||
| 609 | answer.create_device_context.device_context; | ||
| 610 | spin_lock(&(connection->state_lock)); | ||
| 611 | connection->state = TF_CONN_STATE_VALID_DEVICE_CONTEXT; | ||
| 612 | spin_unlock(&(connection->state_lock)); | ||
| 613 | |||
| 614 | /* successful completion */ | ||
| 615 | dprintk(KERN_INFO "tf_create_device_context(%p):" | ||
| 616 | " device_context=0x%08x\n", | ||
| 617 | connection, | ||
| 618 | answer.create_device_context.device_context); | ||
| 619 | return 0; | ||
| 620 | |||
| 621 | error: | ||
| 622 | if (error != 0) { | ||
| 623 | dprintk(KERN_ERR "tf_create_device_context failed with " | ||
| 624 | "error %d\n", error); | ||
| 625 | } else { | ||
| 626 | /* | ||
| 627 | * We sent a DeviceCreateContext. The state is now | ||
| 628 | * TF_CONN_STATE_CREATE_DEVICE_CONTEXT_SENT It has to be | ||
| 629 | * reset if we ever want to send a DeviceCreateContext again | ||
| 630 | */ | ||
| 631 | spin_lock(&(connection->state_lock)); | ||
| 632 | connection->state = TF_CONN_STATE_NO_DEVICE_CONTEXT; | ||
| 633 | spin_unlock(&(connection->state_lock)); | ||
| 634 | dprintk(KERN_ERR "tf_create_device_context failed with " | ||
| 635 | "error_code 0x%08X\n", | ||
| 636 | answer.create_device_context.error_code); | ||
| 637 | if (answer.create_device_context.error_code == | ||
| 638 | S_ERROR_OUT_OF_MEMORY) | ||
| 639 | error = -ENOMEM; | ||
| 640 | else | ||
| 641 | error = -EFAULT; | ||
| 642 | } | ||
| 643 | |||
| 644 | return error; | ||
| 645 | } | ||
| 646 | |||
| 647 | /* Check that the current application belongs to the | ||
| 648 | * requested GID */ | ||
| 649 | static bool tf_check_gid(gid_t requested_gid) | ||
| 650 | { | ||
| 651 | if (requested_gid == current_egid()) { | ||
| 652 | return true; | ||
| 653 | } else { | ||
| 654 | u32 size; | ||
| 655 | u32 i; | ||
| 656 | /* Look in the supplementary GIDs */ | ||
| 657 | get_group_info(GROUP_INFO); | ||
| 658 | size = GROUP_INFO->ngroups; | ||
| 659 | for (i = 0; i < size; i++) | ||
| 660 | if (requested_gid == GROUP_AT(GROUP_INFO , i)) | ||
| 661 | return true; | ||
| 662 | } | ||
| 663 | return false; | ||
| 664 | } | ||
| 665 | |||
| 666 | /* | ||
| 667 | * Opens a client session to the Secure World | ||
| 668 | */ | ||
| 669 | int tf_open_client_session( | ||
| 670 | struct tf_connection *connection, | ||
| 671 | union tf_command *command, | ||
| 672 | union tf_answer *answer) | ||
| 673 | { | ||
| 674 | int error = 0; | ||
| 675 | struct tf_shmem_desc *shmem_desc[4] = {NULL}; | ||
| 676 | u32 i; | ||
| 677 | |||
| 678 | dprintk(KERN_INFO "tf_open_client_session(%p)\n", connection); | ||
| 679 | |||
| 680 | /* | ||
| 681 | * Initialize the message size with no login data. This will be later | ||
| 682 | * adjusted the the cases below | ||
| 683 | */ | ||
| 684 | command->open_client_session.message_size = | ||
| 685 | (sizeof(struct tf_command_open_client_session) - 20 | ||
| 686 | - sizeof(struct tf_command_header))/4; | ||
| 687 | |||
| 688 | switch (command->open_client_session.login_type) { | ||
| 689 | case TF_LOGIN_PUBLIC: | ||
| 690 | /* Nothing to do */ | ||
| 691 | break; | ||
| 692 | |||
| 693 | case TF_LOGIN_USER: | ||
| 694 | /* | ||
| 695 | * Send the EUID of the calling application in the login data. | ||
| 696 | * Update message size. | ||
| 697 | */ | ||
| 698 | *(u32 *) &command->open_client_session.login_data = | ||
| 699 | current_euid(); | ||
| 700 | #ifndef CONFIG_ANDROID | ||
| 701 | command->open_client_session.login_type = | ||
| 702 | (u32) TF_LOGIN_USER_LINUX_EUID; | ||
| 703 | #else | ||
| 704 | command->open_client_session.login_type = | ||
| 705 | (u32) TF_LOGIN_USER_ANDROID_EUID; | ||
| 706 | #endif | ||
| 707 | |||
| 708 | /* Added one word */ | ||
| 709 | command->open_client_session.message_size += 1; | ||
| 710 | break; | ||
| 711 | |||
| 712 | case TF_LOGIN_GROUP: { | ||
| 713 | /* Check requested GID */ | ||
| 714 | gid_t requested_gid = | ||
| 715 | *(u32 *) command->open_client_session.login_data; | ||
| 716 | |||
| 717 | if (!tf_check_gid(requested_gid)) { | ||
| 718 | dprintk(KERN_ERR "tf_open_client_session(%p) " | ||
| 719 | "TF_LOGIN_GROUP: requested GID (0x%x) does " | ||
| 720 | "not match real eGID (0x%x)" | ||
| 721 | "or any of the supplementary GIDs\n", | ||
| 722 | connection, requested_gid, current_egid()); | ||
| 723 | error = -EACCES; | ||
| 724 | goto error; | ||
| 725 | } | ||
| 726 | #ifndef CONFIG_ANDROID | ||
| 727 | command->open_client_session.login_type = | ||
| 728 | TF_LOGIN_GROUP_LINUX_GID; | ||
| 729 | #else | ||
| 730 | command->open_client_session.login_type = | ||
| 731 | TF_LOGIN_GROUP_ANDROID_GID; | ||
| 732 | #endif | ||
| 733 | |||
| 734 | command->open_client_session.message_size += 1; /* GID */ | ||
| 735 | break; | ||
| 736 | } | ||
| 737 | |||
| 738 | #ifndef CONFIG_ANDROID | ||
| 739 | case TF_LOGIN_APPLICATION: { | ||
| 740 | /* | ||
| 741 | * Compute SHA-1 hash of the application fully-qualified path | ||
| 742 | * name. Truncate the hash to 16 bytes and send it as login | ||
| 743 | * data. Update message size. | ||
| 744 | */ | ||
| 745 | u8 pSHA1Hash[SHA1_DIGEST_SIZE]; | ||
| 746 | |||
| 747 | error = tf_hash_application_path_and_data(pSHA1Hash, | ||
| 748 | NULL, 0); | ||
| 749 | if (error != 0) { | ||
| 750 | dprintk(KERN_ERR "tf_open_client_session: " | ||
| 751 | "error in tf_hash_application_path_and_data\n"); | ||
| 752 | goto error; | ||
| 753 | } | ||
| 754 | memcpy(&command->open_client_session.login_data, | ||
| 755 | pSHA1Hash, 16); | ||
| 756 | command->open_client_session.login_type = | ||
| 757 | TF_LOGIN_APPLICATION_LINUX_PATH_SHA1_HASH; | ||
| 758 | /* 16 bytes */ | ||
| 759 | command->open_client_session.message_size += 4; | ||
| 760 | break; | ||
| 761 | } | ||
| 762 | #else | ||
| 763 | case TF_LOGIN_APPLICATION: | ||
| 764 | /* | ||
| 765 | * Send the real UID of the calling application in the login | ||
| 766 | * data. Update message size. | ||
| 767 | */ | ||
| 768 | *(u32 *) &command->open_client_session.login_data = | ||
| 769 | current_uid(); | ||
| 770 | |||
| 771 | command->open_client_session.login_type = | ||
| 772 | (u32) TF_LOGIN_APPLICATION_ANDROID_UID; | ||
| 773 | |||
| 774 | /* Added one word */ | ||
| 775 | command->open_client_session.message_size += 1; | ||
| 776 | break; | ||
| 777 | #endif | ||
| 778 | |||
| 779 | #ifndef CONFIG_ANDROID | ||
| 780 | case TF_LOGIN_APPLICATION_USER: { | ||
| 781 | /* | ||
| 782 | * Compute SHA-1 hash of the concatenation of the application | ||
| 783 | * fully-qualified path name and the EUID of the calling | ||
| 784 | * application. Truncate the hash to 16 bytes and send it as | ||
| 785 | * login data. Update message size. | ||
| 786 | */ | ||
| 787 | u8 pSHA1Hash[SHA1_DIGEST_SIZE]; | ||
| 788 | |||
| 789 | error = tf_hash_application_path_and_data(pSHA1Hash, | ||
| 790 | (u8 *) &(current_euid()), sizeof(current_euid())); | ||
| 791 | if (error != 0) { | ||
| 792 | dprintk(KERN_ERR "tf_open_client_session: " | ||
| 793 | "error in tf_hash_application_path_and_data\n"); | ||
| 794 | goto error; | ||
| 795 | } | ||
| 796 | memcpy(&command->open_client_session.login_data, | ||
| 797 | pSHA1Hash, 16); | ||
| 798 | command->open_client_session.login_type = | ||
| 799 | TF_LOGIN_APPLICATION_USER_LINUX_PATH_EUID_SHA1_HASH; | ||
| 800 | |||
| 801 | /* 16 bytes */ | ||
| 802 | command->open_client_session.message_size += 4; | ||
| 803 | |||
| 804 | break; | ||
| 805 | } | ||
| 806 | #else | ||
| 807 | case TF_LOGIN_APPLICATION_USER: | ||
| 808 | /* | ||
| 809 | * Send the real UID and the EUID of the calling application in | ||
| 810 | * the login data. Update message size. | ||
| 811 | */ | ||
| 812 | *(u32 *) &command->open_client_session.login_data = | ||
| 813 | current_uid(); | ||
| 814 | *(u32 *) &command->open_client_session.login_data[4] = | ||
| 815 | current_euid(); | ||
| 816 | |||
| 817 | command->open_client_session.login_type = | ||
| 818 | TF_LOGIN_APPLICATION_USER_ANDROID_UID_EUID; | ||
| 819 | |||
| 820 | /* Added two words */ | ||
| 821 | command->open_client_session.message_size += 2; | ||
| 822 | break; | ||
| 823 | #endif | ||
| 824 | |||
| 825 | #ifndef CONFIG_ANDROID | ||
| 826 | case TF_LOGIN_APPLICATION_GROUP: { | ||
| 827 | /* | ||
| 828 | * Check requested GID. Compute SHA-1 hash of the concatenation | ||
| 829 | * of the application fully-qualified path name and the | ||
| 830 | * requested GID. Update message size | ||
| 831 | */ | ||
| 832 | gid_t requested_gid; | ||
| 833 | u8 pSHA1Hash[SHA1_DIGEST_SIZE]; | ||
| 834 | |||
| 835 | requested_gid = *(u32 *) &command->open_client_session. | ||
| 836 | login_data; | ||
| 837 | |||
| 838 | if (!tf_check_gid(requested_gid)) { | ||
| 839 | dprintk(KERN_ERR "tf_open_client_session(%p) " | ||
| 840 | "TF_LOGIN_APPLICATION_GROUP: requested GID (0x%x) " | ||
| 841 | "does not match real eGID (0x%x)" | ||
| 842 | "or any of the supplementary GIDs\n", | ||
| 843 | connection, requested_gid, current_egid()); | ||
| 844 | error = -EACCES; | ||
| 845 | goto error; | ||
| 846 | } | ||
| 847 | |||
| 848 | error = tf_hash_application_path_and_data(pSHA1Hash, | ||
| 849 | &requested_gid, sizeof(u32)); | ||
| 850 | if (error != 0) { | ||
| 851 | dprintk(KERN_ERR "tf_open_client_session: " | ||
| 852 | "error in tf_hash_application_path_and_data\n"); | ||
| 853 | goto error; | ||
| 854 | } | ||
| 855 | |||
| 856 | memcpy(&command->open_client_session.login_data, | ||
| 857 | pSHA1Hash, 16); | ||
| 858 | command->open_client_session.login_type = | ||
| 859 | TF_LOGIN_APPLICATION_GROUP_LINUX_PATH_GID_SHA1_HASH; | ||
| 860 | |||
| 861 | /* 16 bytes */ | ||
| 862 | command->open_client_session.message_size += 4; | ||
| 863 | break; | ||
| 864 | } | ||
| 865 | #else | ||
| 866 | case TF_LOGIN_APPLICATION_GROUP: { | ||
| 867 | /* | ||
| 868 | * Check requested GID. Send the real UID and the requested GID | ||
| 869 | * in the login data. Update message size. | ||
| 870 | */ | ||
| 871 | gid_t requested_gid; | ||
| 872 | |||
| 873 | requested_gid = *(u32 *) &command->open_client_session. | ||
| 874 | login_data; | ||
| 875 | |||
| 876 | if (!tf_check_gid(requested_gid)) { | ||
| 877 | dprintk(KERN_ERR "tf_open_client_session(%p) " | ||
| 878 | "TF_LOGIN_APPLICATION_GROUP: requested GID (0x%x) " | ||
| 879 | "does not match real eGID (0x%x)" | ||
| 880 | "or any of the supplementary GIDs\n", | ||
| 881 | connection, requested_gid, current_egid()); | ||
| 882 | error = -EACCES; | ||
| 883 | goto error; | ||
| 884 | } | ||
| 885 | |||
| 886 | *(u32 *) &command->open_client_session.login_data = | ||
| 887 | current_uid(); | ||
| 888 | *(u32 *) &command->open_client_session.login_data[4] = | ||
| 889 | requested_gid; | ||
| 890 | |||
| 891 | command->open_client_session.login_type = | ||
| 892 | TF_LOGIN_APPLICATION_GROUP_ANDROID_UID_GID; | ||
| 893 | |||
| 894 | /* Added two words */ | ||
| 895 | command->open_client_session.message_size += 2; | ||
| 896 | |||
| 897 | break; | ||
| 898 | } | ||
| 899 | #endif | ||
| 900 | |||
| 901 | case TF_LOGIN_PRIVILEGED: | ||
| 902 | /* A privileged login may be performed only on behalf of the | ||
| 903 | kernel itself or on behalf of a process with euid=0 or | ||
| 904 | egid=0 or euid=system or egid=system. */ | ||
| 905 | if (connection->owner == TF_CONNECTION_OWNER_KERNEL) { | ||
| 906 | dprintk(KERN_DEBUG "tf_open_client_session: " | ||
| 907 | "TF_LOGIN_PRIVILEGED for kernel API\n"); | ||
| 908 | } else if ((current_euid() != TF_PRIVILEGED_UID_GID) && | ||
| 909 | (current_egid() != TF_PRIVILEGED_UID_GID) && | ||
| 910 | (current_euid() != 0) && (current_egid() != 0)) { | ||
| 911 | dprintk(KERN_ERR "tf_open_client_session: " | ||
| 912 | " user %d, group %d not allowed to open " | ||
| 913 | "session with TF_LOGIN_PRIVILEGED\n", | ||
| 914 | current_euid(), current_egid()); | ||
| 915 | error = -EACCES; | ||
| 916 | goto error; | ||
| 917 | } else { | ||
| 918 | dprintk(KERN_DEBUG "tf_open_client_session: " | ||
| 919 | "TF_LOGIN_PRIVILEGED for %u:%u\n", | ||
| 920 | current_euid(), current_egid()); | ||
| 921 | } | ||
| 922 | command->open_client_session.login_type = | ||
| 923 | TF_LOGIN_PRIVILEGED; | ||
| 924 | break; | ||
| 925 | |||
| 926 | case TF_LOGIN_AUTHENTICATION: { | ||
| 927 | /* | ||
| 928 | * Compute SHA-1 hash of the application binary | ||
| 929 | * Send this hash as the login data (20 bytes) | ||
| 930 | */ | ||
| 931 | |||
| 932 | u8 *hash; | ||
| 933 | hash = &(command->open_client_session.login_data[0]); | ||
| 934 | |||
| 935 | error = tf_get_current_process_hash(hash); | ||
| 936 | if (error != 0) { | ||
| 937 | dprintk(KERN_ERR "tf_open_client_session: " | ||
| 938 | "error in tf_get_current_process_hash\n"); | ||
| 939 | goto error; | ||
| 940 | } | ||
| 941 | command->open_client_session.login_type = | ||
| 942 | TF_LOGIN_AUTHENTICATION_BINARY_SHA1_HASH; | ||
| 943 | |||
| 944 | /* 20 bytes */ | ||
| 945 | command->open_client_session.message_size += 5; | ||
| 946 | break; | ||
| 947 | } | ||
| 948 | |||
| 949 | case TF_LOGIN_PRIVILEGED_KERNEL: | ||
| 950 | /* A kernel login may be performed only on behalf of the | ||
| 951 | kernel itself. */ | ||
| 952 | if (connection->owner == TF_CONNECTION_OWNER_KERNEL) { | ||
| 953 | dprintk(KERN_DEBUG "tf_open_client_session: " | ||
| 954 | "TF_LOGIN_PRIVILEGED_KERNEL for kernel API\n"); | ||
| 955 | command->open_client_session.login_type = | ||
| 956 | TF_LOGIN_PRIVILEGED_KERNEL; | ||
| 957 | } else { | ||
| 958 | dprintk(KERN_ERR "tf_open_client_session: " | ||
| 959 | " user %d, group %d not allowed to open " | ||
| 960 | "session with TF_LOGIN_PRIVILEGED_KERNEL\n", | ||
| 961 | current_euid(), current_egid()); | ||
| 962 | error = -EACCES; | ||
| 963 | goto error; | ||
| 964 | } | ||
| 965 | command->open_client_session.login_type = | ||
| 966 | TF_LOGIN_PRIVILEGED_KERNEL; | ||
| 967 | break; | ||
| 968 | |||
| 969 | default: | ||
| 970 | dprintk(KERN_ERR "tf_open_client_session: " | ||
| 971 | "unknown login_type(%08X)\n", | ||
| 972 | command->open_client_session.login_type); | ||
| 973 | error = -EOPNOTSUPP; | ||
| 974 | goto error; | ||
| 975 | } | ||
| 976 | |||
| 977 | /* Map the temporary memory references */ | ||
| 978 | for (i = 0; i < 4; i++) { | ||
| 979 | int param_type; | ||
| 980 | param_type = TF_GET_PARAM_TYPE( | ||
| 981 | command->open_client_session.param_types, i); | ||
| 982 | if ((param_type & (TF_PARAM_TYPE_MEMREF_FLAG | | ||
| 983 | TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG)) | ||
| 984 | == TF_PARAM_TYPE_MEMREF_FLAG) { | ||
| 985 | /* Map temp mem ref */ | ||
| 986 | error = tf_map_temp_shmem(connection, | ||
| 987 | &command->open_client_session. | ||
| 988 | params[i].temp_memref, | ||
| 989 | param_type, | ||
| 990 | &shmem_desc[i]); | ||
| 991 | if (error != 0) { | ||
| 992 | dprintk(KERN_ERR "tf_open_client_session: " | ||
| 993 | "unable to map temporary memory block " | ||
| 994 | "(%08X)\n", error); | ||
| 995 | goto error; | ||
| 996 | } | ||
| 997 | } | ||
| 998 | } | ||
| 999 | |||
| 1000 | /* Fill the handle of the Device Context */ | ||
| 1001 | command->open_client_session.device_context = | ||
| 1002 | connection->device_context; | ||
| 1003 | |||
| 1004 | error = tf_send_receive( | ||
| 1005 | &connection->dev->sm, | ||
| 1006 | command, | ||
| 1007 | answer, | ||
| 1008 | connection, | ||
| 1009 | true); | ||
| 1010 | |||
| 1011 | error: | ||
| 1012 | /* Unmap the temporary memory references */ | ||
| 1013 | for (i = 0; i < 4; i++) | ||
| 1014 | if (shmem_desc[i] != NULL) | ||
| 1015 | tf_unmap_shmem(connection, shmem_desc[i], 0); | ||
| 1016 | |||
| 1017 | if (error != 0) | ||
| 1018 | dprintk(KERN_ERR "tf_open_client_session returns %d\n", | ||
| 1019 | error); | ||
| 1020 | else | ||
| 1021 | dprintk(KERN_ERR "tf_open_client_session returns " | ||
| 1022 | "error_code 0x%08X\n", | ||
| 1023 | answer->open_client_session.error_code); | ||
| 1024 | |||
| 1025 | return error; | ||
| 1026 | } | ||
| 1027 | |||
| 1028 | |||
| 1029 | /* | ||
| 1030 | * Closes a client session from the Secure World | ||
| 1031 | */ | ||
| 1032 | int tf_close_client_session( | ||
| 1033 | struct tf_connection *connection, | ||
| 1034 | union tf_command *command, | ||
| 1035 | union tf_answer *answer) | ||
| 1036 | { | ||
| 1037 | int error = 0; | ||
| 1038 | |||
| 1039 | dprintk(KERN_DEBUG "tf_close_client_session(%p)\n", connection); | ||
| 1040 | |||
| 1041 | command->close_client_session.message_size = | ||
| 1042 | (sizeof(struct tf_command_close_client_session) - | ||
| 1043 | sizeof(struct tf_command_header)) / 4; | ||
| 1044 | command->close_client_session.device_context = | ||
| 1045 | connection->device_context; | ||
| 1046 | |||
| 1047 | error = tf_send_receive( | ||
| 1048 | &connection->dev->sm, | ||
| 1049 | command, | ||
| 1050 | answer, | ||
| 1051 | connection, | ||
| 1052 | true); | ||
| 1053 | |||
| 1054 | if (error != 0) | ||
| 1055 | dprintk(KERN_ERR "tf_close_client_session returns %d\n", | ||
| 1056 | error); | ||
| 1057 | else | ||
| 1058 | dprintk(KERN_ERR "tf_close_client_session returns " | ||
| 1059 | "error 0x%08X\n", | ||
| 1060 | answer->close_client_session.error_code); | ||
| 1061 | |||
| 1062 | return error; | ||
| 1063 | } | ||
| 1064 | |||
| 1065 | |||
| 1066 | /* | ||
| 1067 | * Registers a shared memory to the Secure World | ||
| 1068 | */ | ||
| 1069 | int tf_register_shared_memory( | ||
| 1070 | struct tf_connection *connection, | ||
| 1071 | union tf_command *command, | ||
| 1072 | union tf_answer *answer) | ||
| 1073 | { | ||
| 1074 | int error = 0; | ||
| 1075 | struct tf_shmem_desc *shmem_desc = NULL; | ||
| 1076 | bool in_user_space = connection->owner != TF_CONNECTION_OWNER_KERNEL; | ||
| 1077 | struct tf_command_register_shared_memory *msg = | ||
| 1078 | &command->register_shared_memory; | ||
| 1079 | |||
| 1080 | dprintk(KERN_INFO "tf_register_shared_memory(%p) " | ||
| 1081 | "%p[0x%08X][0x%08x]\n", | ||
| 1082 | connection, | ||
| 1083 | (void *)msg->shared_mem_descriptors[0], | ||
| 1084 | msg->shared_mem_size, | ||
| 1085 | (u32)msg->memory_flags); | ||
| 1086 | |||
| 1087 | if (in_user_space) { | ||
| 1088 | error = tf_validate_shmem_and_flags( | ||
| 1089 | msg->shared_mem_descriptors[0], | ||
| 1090 | msg->shared_mem_size, | ||
| 1091 | (u32)msg->memory_flags); | ||
| 1092 | if (error != 0) | ||
| 1093 | goto error; | ||
| 1094 | } | ||
| 1095 | |||
| 1096 | /* Initialize message_size with no descriptors */ | ||
| 1097 | msg->message_size | ||
| 1098 | = (offsetof(struct tf_command_register_shared_memory, | ||
| 1099 | shared_mem_descriptors) - | ||
| 1100 | sizeof(struct tf_command_header)) / 4; | ||
| 1101 | |||
| 1102 | /* Map the shmem block and update the message */ | ||
| 1103 | if (msg->shared_mem_size == 0) { | ||
| 1104 | /* Empty shared mem */ | ||
| 1105 | msg->shared_mem_start_offset = msg->shared_mem_descriptors[0]; | ||
| 1106 | } else { | ||
| 1107 | u32 descriptor_count; | ||
| 1108 | error = tf_map_shmem( | ||
| 1109 | connection, | ||
| 1110 | msg->shared_mem_descriptors[0], | ||
| 1111 | msg->memory_flags, | ||
| 1112 | in_user_space, | ||
| 1113 | msg->shared_mem_descriptors, | ||
| 1114 | &(msg->shared_mem_start_offset), | ||
| 1115 | msg->shared_mem_size, | ||
| 1116 | &shmem_desc, | ||
| 1117 | &descriptor_count); | ||
| 1118 | if (error != 0) { | ||
| 1119 | dprintk(KERN_ERR "tf_register_shared_memory: " | ||
| 1120 | "unable to map shared memory block\n"); | ||
| 1121 | goto error; | ||
| 1122 | } | ||
| 1123 | msg->message_size += descriptor_count; | ||
| 1124 | } | ||
| 1125 | |||
| 1126 | /* | ||
| 1127 | * write the correct device context handle and the address of the shared | ||
| 1128 | * memory descriptor in the message | ||
| 1129 | */ | ||
| 1130 | msg->device_context = connection->device_context; | ||
| 1131 | msg->block_id = (u32)shmem_desc; | ||
| 1132 | |||
| 1133 | /* Send the updated message */ | ||
| 1134 | error = tf_send_receive( | ||
| 1135 | &connection->dev->sm, | ||
| 1136 | command, | ||
| 1137 | answer, | ||
| 1138 | connection, | ||
| 1139 | true); | ||
| 1140 | |||
| 1141 | if ((error != 0) || | ||
| 1142 | (answer->register_shared_memory.error_code | ||
| 1143 | != S_SUCCESS)) { | ||
| 1144 | dprintk(KERN_ERR "tf_register_shared_memory: " | ||
| 1145 | "operation failed. Unmap block\n"); | ||
| 1146 | goto error; | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | /* Saves the block handle returned by the secure world */ | ||
| 1150 | if (shmem_desc != NULL) | ||
| 1151 | shmem_desc->block_identifier = | ||
| 1152 | answer->register_shared_memory.block; | ||
| 1153 | |||
| 1154 | /* successful completion */ | ||
| 1155 | dprintk(KERN_INFO "tf_register_shared_memory(%p):" | ||
| 1156 | " block_id=0x%08x block=0x%08x\n", | ||
| 1157 | connection, msg->block_id, | ||
| 1158 | answer->register_shared_memory.block); | ||
| 1159 | return 0; | ||
| 1160 | |||
| 1161 | /* error completion */ | ||
| 1162 | error: | ||
| 1163 | tf_unmap_shmem( | ||
| 1164 | connection, | ||
| 1165 | shmem_desc, | ||
| 1166 | 0); | ||
| 1167 | |||
| 1168 | if (error != 0) | ||
| 1169 | dprintk(KERN_ERR "tf_register_shared_memory returns %d\n", | ||
| 1170 | error); | ||
| 1171 | else | ||
| 1172 | dprintk(KERN_ERR "tf_register_shared_memory returns " | ||
| 1173 | "error_code 0x%08X\n", | ||
| 1174 | answer->register_shared_memory.error_code); | ||
| 1175 | |||
| 1176 | return error; | ||
| 1177 | } | ||
| 1178 | |||
| 1179 | |||
| 1180 | /* | ||
| 1181 | * Releases a shared memory from the Secure World | ||
| 1182 | */ | ||
| 1183 | int tf_release_shared_memory( | ||
| 1184 | struct tf_connection *connection, | ||
| 1185 | union tf_command *command, | ||
| 1186 | union tf_answer *answer) | ||
| 1187 | { | ||
| 1188 | int error = 0; | ||
| 1189 | |||
| 1190 | dprintk(KERN_DEBUG "tf_release_shared_memory(%p)\n", connection); | ||
| 1191 | |||
| 1192 | command->release_shared_memory.message_size = | ||
| 1193 | (sizeof(struct tf_command_release_shared_memory) - | ||
| 1194 | sizeof(struct tf_command_header)) / 4; | ||
| 1195 | command->release_shared_memory.device_context = | ||
| 1196 | connection->device_context; | ||
| 1197 | |||
| 1198 | error = tf_send_receive( | ||
| 1199 | &connection->dev->sm, | ||
| 1200 | command, | ||
| 1201 | answer, | ||
| 1202 | connection, | ||
| 1203 | true); | ||
| 1204 | |||
| 1205 | if ((error != 0) || | ||
| 1206 | (answer->release_shared_memory.error_code != S_SUCCESS)) | ||
| 1207 | goto error; | ||
| 1208 | |||
| 1209 | /* Use block_id to get back the pointer to shmem_desc */ | ||
| 1210 | tf_unmap_shmem( | ||
| 1211 | connection, | ||
| 1212 | (struct tf_shmem_desc *) | ||
| 1213 | answer->release_shared_memory.block_id, | ||
| 1214 | 0); | ||
| 1215 | |||
| 1216 | /* successful completion */ | ||
| 1217 | dprintk(KERN_INFO "tf_release_shared_memory(%p):" | ||
| 1218 | " block_id=0x%08x block=0x%08x\n", | ||
| 1219 | connection, answer->release_shared_memory.block_id, | ||
| 1220 | command->release_shared_memory.block); | ||
| 1221 | return 0; | ||
| 1222 | |||
| 1223 | |||
| 1224 | error: | ||
| 1225 | if (error != 0) | ||
| 1226 | dprintk(KERN_ERR "tf_release_shared_memory returns %d\n", | ||
| 1227 | error); | ||
| 1228 | else | ||
| 1229 | dprintk(KERN_ERR "tf_release_shared_memory returns " | ||
| 1230 | "nChannelStatus 0x%08X\n", | ||
| 1231 | answer->release_shared_memory.error_code); | ||
| 1232 | |||
| 1233 | return error; | ||
| 1234 | |||
| 1235 | } | ||
| 1236 | |||
| 1237 | |||
| 1238 | /* | ||
| 1239 | * Invokes a client command to the Secure World | ||
| 1240 | */ | ||
| 1241 | int tf_invoke_client_command( | ||
| 1242 | struct tf_connection *connection, | ||
| 1243 | union tf_command *command, | ||
| 1244 | union tf_answer *answer) | ||
| 1245 | { | ||
| 1246 | int error = 0; | ||
| 1247 | struct tf_shmem_desc *shmem_desc[4] = {NULL}; | ||
| 1248 | int i; | ||
| 1249 | |||
| 1250 | dprintk(KERN_INFO "tf_invoke_client_command(%p)\n", connection); | ||
| 1251 | |||
| 1252 | command->release_shared_memory.message_size = | ||
| 1253 | (sizeof(struct tf_command_invoke_client_command) - | ||
| 1254 | sizeof(struct tf_command_header)) / 4; | ||
| 1255 | |||
| 1256 | #ifdef CONFIG_TF_ZEBRA | ||
| 1257 | error = tf_crypto_try_shortcuted_update(connection, | ||
| 1258 | (struct tf_command_invoke_client_command *) command, | ||
| 1259 | (struct tf_answer_invoke_client_command *) answer); | ||
| 1260 | if (error == 0) | ||
| 1261 | return error; | ||
| 1262 | #endif | ||
| 1263 | |||
| 1264 | /* Map the tmprefs */ | ||
| 1265 | for (i = 0; i < 4; i++) { | ||
| 1266 | int param_type = TF_GET_PARAM_TYPE( | ||
| 1267 | command->invoke_client_command.param_types, i); | ||
| 1268 | if ((param_type & (TF_PARAM_TYPE_MEMREF_FLAG | | ||
| 1269 | TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG)) | ||
| 1270 | == TF_PARAM_TYPE_MEMREF_FLAG) { | ||
| 1271 | /* A temporary memref: map it */ | ||
| 1272 | error = tf_map_temp_shmem(connection, | ||
| 1273 | &command->invoke_client_command. | ||
| 1274 | params[i].temp_memref, | ||
| 1275 | param_type, &shmem_desc[i]); | ||
| 1276 | if (error != 0) { | ||
| 1277 | dprintk(KERN_ERR | ||
| 1278 | "tf_invoke_client_command: " | ||
| 1279 | "unable to map temporary memory " | ||
| 1280 | "block\n (%08X)", error); | ||
| 1281 | goto error; | ||
| 1282 | } | ||
| 1283 | } | ||
| 1284 | } | ||
| 1285 | |||
| 1286 | command->invoke_client_command.device_context = | ||
| 1287 | connection->device_context; | ||
| 1288 | |||
| 1289 | error = tf_send_receive(&connection->dev->sm, command, | ||
| 1290 | answer, connection, true); | ||
| 1291 | |||
| 1292 | error: | ||
| 1293 | /* Unmap de temp mem refs */ | ||
| 1294 | for (i = 0; i < 4; i++) { | ||
| 1295 | if (shmem_desc[i] != NULL) { | ||
| 1296 | dprintk(KERN_INFO "tf_invoke_client_command: " | ||
| 1297 | "UnMatemp_memref %d\n ", i); | ||
| 1298 | tf_unmap_shmem(connection, shmem_desc[i], 0); | ||
| 1299 | } | ||
| 1300 | } | ||
| 1301 | |||
| 1302 | if (error != 0) | ||
| 1303 | dprintk(KERN_ERR "tf_invoke_client_command returns %d\n", | ||
| 1304 | error); | ||
| 1305 | else | ||
| 1306 | dprintk(KERN_ERR "tf_invoke_client_command returns " | ||
| 1307 | "error_code 0x%08X\n", | ||
| 1308 | answer->invoke_client_command.error_code); | ||
| 1309 | |||
| 1310 | return error; | ||
| 1311 | } | ||
| 1312 | |||
| 1313 | |||
| 1314 | /* | ||
| 1315 | * Cancels a client command from the Secure World | ||
| 1316 | */ | ||
| 1317 | int tf_cancel_client_command( | ||
| 1318 | struct tf_connection *connection, | ||
| 1319 | union tf_command *command, | ||
| 1320 | union tf_answer *answer) | ||
| 1321 | { | ||
| 1322 | int error = 0; | ||
| 1323 | |||
| 1324 | dprintk(KERN_DEBUG "tf_cancel_client_command(%p)\n", connection); | ||
| 1325 | |||
| 1326 | command->cancel_client_operation.device_context = | ||
| 1327 | connection->device_context; | ||
| 1328 | command->cancel_client_operation.message_size = | ||
| 1329 | (sizeof(struct tf_command_cancel_client_operation) - | ||
| 1330 | sizeof(struct tf_command_header)) / 4; | ||
| 1331 | |||
| 1332 | error = tf_send_receive( | ||
| 1333 | &connection->dev->sm, | ||
| 1334 | command, | ||
| 1335 | answer, | ||
| 1336 | connection, | ||
| 1337 | true); | ||
| 1338 | |||
| 1339 | if ((error != 0) || | ||
| 1340 | (answer->cancel_client_operation.error_code != S_SUCCESS)) | ||
| 1341 | goto error; | ||
| 1342 | |||
| 1343 | |||
| 1344 | /* successful completion */ | ||
| 1345 | return 0; | ||
| 1346 | |||
| 1347 | error: | ||
| 1348 | if (error != 0) | ||
| 1349 | dprintk(KERN_ERR "tf_cancel_client_command returns %d\n", | ||
| 1350 | error); | ||
| 1351 | else | ||
| 1352 | dprintk(KERN_ERR "tf_cancel_client_command returns " | ||
| 1353 | "nChannelStatus 0x%08X\n", | ||
| 1354 | answer->cancel_client_operation.error_code); | ||
| 1355 | |||
| 1356 | return error; | ||
| 1357 | } | ||
| 1358 | |||
| 1359 | |||
| 1360 | |||
| 1361 | /* | ||
| 1362 | * Destroys a device context from the Secure World | ||
| 1363 | */ | ||
| 1364 | int tf_destroy_device_context( | ||
| 1365 | struct tf_connection *connection) | ||
| 1366 | { | ||
| 1367 | int error; | ||
| 1368 | /* | ||
| 1369 | * AFY: better use the specialized tf_command_destroy_device_context | ||
| 1370 | * structure: this will save stack | ||
| 1371 | */ | ||
| 1372 | union tf_command command; | ||
| 1373 | union tf_answer answer; | ||
| 1374 | |||
| 1375 | dprintk(KERN_INFO "tf_destroy_device_context(%p)\n", connection); | ||
| 1376 | |||
| 1377 | BUG_ON(connection == NULL); | ||
| 1378 | |||
| 1379 | command.header.message_type = TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT; | ||
| 1380 | command.header.message_size = | ||
| 1381 | (sizeof(struct tf_command_destroy_device_context) - | ||
| 1382 | sizeof(struct tf_command_header))/sizeof(u32); | ||
| 1383 | |||
| 1384 | /* | ||
| 1385 | * fill in the device context handler | ||
| 1386 | * it is guarantied that the first shared memory descriptor describes | ||
| 1387 | * the device context | ||
| 1388 | */ | ||
| 1389 | command.destroy_device_context.device_context = | ||
| 1390 | connection->device_context; | ||
| 1391 | |||
| 1392 | error = tf_send_receive( | ||
| 1393 | &connection->dev->sm, | ||
| 1394 | &command, | ||
| 1395 | &answer, | ||
| 1396 | connection, | ||
| 1397 | false); | ||
| 1398 | |||
| 1399 | if ((error != 0) || | ||
| 1400 | (answer.destroy_device_context.error_code != S_SUCCESS)) | ||
| 1401 | goto error; | ||
| 1402 | |||
| 1403 | spin_lock(&(connection->state_lock)); | ||
| 1404 | connection->state = TF_CONN_STATE_NO_DEVICE_CONTEXT; | ||
| 1405 | spin_unlock(&(connection->state_lock)); | ||
| 1406 | |||
| 1407 | /* successful completion */ | ||
| 1408 | dprintk(KERN_INFO "tf_destroy_device_context(%p)\n", | ||
| 1409 | connection); | ||
| 1410 | return 0; | ||
| 1411 | |||
| 1412 | error: | ||
| 1413 | if (error != 0) { | ||
| 1414 | dprintk(KERN_ERR "tf_destroy_device_context failed with " | ||
| 1415 | "error %d\n", error); | ||
| 1416 | } else { | ||
| 1417 | dprintk(KERN_ERR "tf_destroy_device_context failed with " | ||
| 1418 | "error_code 0x%08X\n", | ||
| 1419 | answer.destroy_device_context.error_code); | ||
| 1420 | if (answer.destroy_device_context.error_code == | ||
| 1421 | S_ERROR_OUT_OF_MEMORY) | ||
| 1422 | error = -ENOMEM; | ||
| 1423 | else | ||
| 1424 | error = -EFAULT; | ||
| 1425 | } | ||
| 1426 | |||
| 1427 | return error; | ||
| 1428 | } | ||
| 1429 | |||
| 1430 | |||
| 1431 | /*---------------------------------------------------------------------------- | ||
| 1432 | * Connection initialization and cleanup operations | ||
| 1433 | *----------------------------------------------------------------------------*/ | ||
| 1434 | |||
| 1435 | /* | ||
| 1436 | * Opens a connection to the specified device. | ||
| 1437 | * | ||
| 1438 | * The placeholder referenced by connection is set to the address of the | ||
| 1439 | * new connection; it is set to NULL upon failure. | ||
| 1440 | * | ||
| 1441 | * Returns zero upon successful completion, or an appropriate error code upon | ||
| 1442 | * failure. | ||
| 1443 | */ | ||
| 1444 | int tf_open(struct tf_device *dev, | ||
| 1445 | struct file *file, | ||
| 1446 | struct tf_connection **connection) | ||
| 1447 | { | ||
| 1448 | int error; | ||
| 1449 | struct tf_connection *conn = NULL; | ||
| 1450 | |||
| 1451 | dprintk(KERN_INFO "tf_open(%p, %p)\n", file, connection); | ||
| 1452 | |||
| 1453 | /* | ||
| 1454 | * Allocate and initialize the conn. | ||
| 1455 | * kmalloc only allocates sizeof(*conn) virtual memory | ||
| 1456 | */ | ||
| 1457 | conn = (struct tf_connection *) internal_kmalloc(sizeof(*conn), | ||
| 1458 | GFP_KERNEL); | ||
| 1459 | if (conn == NULL) { | ||
| 1460 | printk(KERN_ERR "tf_open(): " | ||
| 1461 | "Out of memory for conn!\n"); | ||
| 1462 | error = -ENOMEM; | ||
| 1463 | goto error; | ||
| 1464 | } | ||
| 1465 | |||
| 1466 | memset(conn, 0, sizeof(*conn)); | ||
| 1467 | |||
| 1468 | conn->state = TF_CONN_STATE_NO_DEVICE_CONTEXT; | ||
| 1469 | conn->dev = dev; | ||
| 1470 | spin_lock_init(&(conn->state_lock)); | ||
| 1471 | atomic_set(&(conn->pending_op_count), 0); | ||
| 1472 | INIT_LIST_HEAD(&(conn->list)); | ||
| 1473 | |||
| 1474 | /* | ||
| 1475 | * Initialize the shared memory | ||
| 1476 | */ | ||
| 1477 | error = tf_init_shared_memory(conn); | ||
| 1478 | if (error != 0) | ||
| 1479 | goto error; | ||
| 1480 | |||
| 1481 | #ifdef CONFIG_TF_ZEBRA | ||
| 1482 | /* | ||
| 1483 | * Initialize CUS specifics | ||
| 1484 | */ | ||
| 1485 | tf_crypto_init_cus(conn); | ||
| 1486 | #endif | ||
| 1487 | |||
| 1488 | /* | ||
| 1489 | * Attach the conn to the device. | ||
| 1490 | */ | ||
| 1491 | spin_lock(&(dev->connection_list_lock)); | ||
| 1492 | list_add(&(conn->list), &(dev->connection_list)); | ||
| 1493 | spin_unlock(&(dev->connection_list_lock)); | ||
| 1494 | |||
| 1495 | /* | ||
| 1496 | * Successful completion. | ||
| 1497 | */ | ||
| 1498 | |||
| 1499 | *connection = conn; | ||
| 1500 | |||
| 1501 | dprintk(KERN_INFO "tf_open(): Success (conn=%p)\n", conn); | ||
| 1502 | return 0; | ||
| 1503 | |||
| 1504 | /* | ||
| 1505 | * Error handling. | ||
| 1506 | */ | ||
| 1507 | |||
| 1508 | error: | ||
| 1509 | dprintk(KERN_ERR "tf_open(): Failure (error %d)\n", error); | ||
| 1510 | /* Deallocate the descriptor pages if necessary */ | ||
| 1511 | internal_kfree(conn); | ||
| 1512 | *connection = NULL; | ||
| 1513 | return error; | ||
| 1514 | } | ||
| 1515 | |||
| 1516 | |||
| 1517 | /* | ||
| 1518 | * Closes the specified connection. | ||
| 1519 | * | ||
| 1520 | * Upon return, the connection has been destroyed and cannot be used anymore. | ||
| 1521 | * | ||
| 1522 | * This function does nothing if connection is set to NULL. | ||
| 1523 | */ | ||
| 1524 | void tf_close(struct tf_connection *connection) | ||
| 1525 | { | ||
| 1526 | int error; | ||
| 1527 | enum TF_CONN_STATE state; | ||
| 1528 | |||
| 1529 | dprintk(KERN_DEBUG "tf_close(%p)\n", connection); | ||
| 1530 | |||
| 1531 | if (connection == NULL) | ||
| 1532 | return; | ||
| 1533 | |||
| 1534 | /* | ||
| 1535 | * Assumption: Linux guarantees that no other operation is in progress | ||
| 1536 | * and that no other operation will be started when close is called | ||
| 1537 | */ | ||
| 1538 | BUG_ON(atomic_read(&(connection->pending_op_count)) != 0); | ||
| 1539 | |||
| 1540 | /* | ||
| 1541 | * Exchange a Destroy Device Context message if needed. | ||
| 1542 | */ | ||
| 1543 | spin_lock(&(connection->state_lock)); | ||
| 1544 | state = connection->state; | ||
| 1545 | spin_unlock(&(connection->state_lock)); | ||
| 1546 | if (state == TF_CONN_STATE_VALID_DEVICE_CONTEXT) { | ||
| 1547 | /* | ||
| 1548 | * A DestroyDeviceContext operation was not performed. Do it | ||
| 1549 | * now. | ||
| 1550 | */ | ||
| 1551 | error = tf_destroy_device_context(connection); | ||
| 1552 | if (error != 0) | ||
| 1553 | /* avoid cleanup if destroy device context fails */ | ||
| 1554 | goto error; | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | /* | ||
| 1558 | * Clean up the shared memory | ||
| 1559 | */ | ||
| 1560 | tf_cleanup_shared_memories(connection); | ||
| 1561 | |||
| 1562 | spin_lock(&(connection->dev->connection_list_lock)); | ||
| 1563 | list_del(&(connection->list)); | ||
| 1564 | spin_unlock(&(connection->dev->connection_list_lock)); | ||
| 1565 | |||
| 1566 | internal_kfree(connection); | ||
| 1567 | |||
| 1568 | return; | ||
| 1569 | |||
| 1570 | error: | ||
| 1571 | dprintk(KERN_DEBUG "tf_close(%p) failed with error code %d\n", | ||
| 1572 | connection, error); | ||
| 1573 | } | ||
| 1574 | |||
diff --git a/security/tf_driver/tf_conn.h b/security/tf_driver/tf_conn.h new file mode 100644 index 00000000000..8bed16f19d5 --- /dev/null +++ b/security/tf_driver/tf_conn.h | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | /** | ||
| 2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 17 | * MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef __TF_CONN_H__ | ||
| 21 | #define __TF_CONN_H__ | ||
| 22 | |||
| 23 | #include "tf_defs.h" | ||
| 24 | |||
| 25 | /* | ||
| 26 | * Returns a pointer to the connection referenced by the | ||
| 27 | * specified file. | ||
| 28 | */ | ||
| 29 | static inline struct tf_connection *tf_conn_from_file( | ||
| 30 | struct file *file) | ||
| 31 | { | ||
| 32 | return file->private_data; | ||
| 33 | } | ||
| 34 | |||
| 35 | int tf_validate_shmem_and_flags(u32 shmem, u32 shmem_size, u32 flags); | ||
| 36 | |||
| 37 | int tf_map_shmem( | ||
| 38 | struct tf_connection *connection, | ||
| 39 | u32 buffer, | ||
| 40 | /* flags for read-write access rights on the memory */ | ||
| 41 | u32 flags, | ||
| 42 | bool in_user_space, | ||
| 43 | u32 descriptors[TF_MAX_COARSE_PAGES], | ||
| 44 | u32 *buffer_start_offset, | ||
| 45 | u32 buffer_size, | ||
| 46 | struct tf_shmem_desc **shmem_desc, | ||
| 47 | u32 *descriptor_count); | ||
| 48 | |||
| 49 | void tf_unmap_shmem( | ||
| 50 | struct tf_connection *connection, | ||
| 51 | struct tf_shmem_desc *shmem_desc, | ||
| 52 | u32 full_cleanup); | ||
| 53 | |||
| 54 | /*---------------------------------------------------------------------------- | ||
| 55 | * Connection operations to the Secure World | ||
| 56 | *----------------------------------------------------------------------------*/ | ||
| 57 | |||
| 58 | int tf_create_device_context( | ||
| 59 | struct tf_connection *connection); | ||
| 60 | |||
| 61 | int tf_destroy_device_context( | ||
| 62 | struct tf_connection *connection); | ||
| 63 | |||
| 64 | int tf_open_client_session( | ||
| 65 | struct tf_connection *connection, | ||
| 66 | union tf_command *command, | ||
| 67 | union tf_answer *answer); | ||
| 68 | |||
| 69 | int tf_close_client_session( | ||
| 70 | struct tf_connection *connection, | ||
| 71 | union tf_command *command, | ||
| 72 | union tf_answer *answer); | ||
| 73 | |||
| 74 | int tf_register_shared_memory( | ||
| 75 | struct tf_connection *connection, | ||
| 76 | union tf_command *command, | ||
| 77 | union tf_answer *answer); | ||
| 78 | |||
| 79 | int tf_release_shared_memory( | ||
| 80 | struct tf_connection *connection, | ||
| 81 | union tf_command *command, | ||
| 82 | union tf_answer *answer); | ||
| 83 | |||
| 84 | int tf_invoke_client_command( | ||
| 85 | struct tf_connection *connection, | ||
| 86 | union tf_command *command, | ||
| 87 | union tf_answer *answer); | ||
| 88 | |||
| 89 | int tf_cancel_client_command( | ||
| 90 | struct tf_connection *connection, | ||
| 91 | union tf_command *command, | ||
| 92 | union tf_answer *answer); | ||
| 93 | |||
| 94 | /*---------------------------------------------------------------------------- | ||
| 95 | * Connection initialization and cleanup operations | ||
| 96 | *----------------------------------------------------------------------------*/ | ||
| 97 | |||
| 98 | int tf_open(struct tf_device *dev, | ||
| 99 | struct file *file, | ||
| 100 | struct tf_connection **connection); | ||
| 101 | |||
| 102 | void tf_close( | ||
| 103 | struct tf_connection *connection); | ||
| 104 | |||
| 105 | |||
| 106 | #endif /* !defined(__TF_CONN_H__) */ | ||
diff --git a/security/tf_driver/tf_defs.h b/security/tf_driver/tf_defs.h new file mode 100644 index 00000000000..ac209370c55 --- /dev/null +++ b/security/tf_driver/tf_defs.h | |||
| @@ -0,0 +1,538 @@ | |||
| 1 | /** | ||
| 2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 17 | * MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef __TF_DEFS_H__ | ||
| 21 | #define __TF_DEFS_H__ | ||
| 22 | |||
| 23 | #include <linux/atomic.h> | ||
| 24 | #include <linux/version.h> | ||
| 25 | #include <linux/fs.h> | ||
| 26 | #include <linux/cdev.h> | ||
| 27 | #include <linux/completion.h> | ||
| 28 | #include <linux/list.h> | ||
| 29 | #include <linux/spinlock.h> | ||
| 30 | #include <linux/sysfs.h> | ||
| 31 | #include <linux/sched.h> | ||
| 32 | #include <linux/semaphore.h> | ||
| 33 | #ifdef CONFIG_HAS_WAKELOCK | ||
| 34 | #include <linux/wakelock.h> | ||
| 35 | #endif | ||
| 36 | |||
| 37 | #include "tf_protocol.h" | ||
| 38 | |||
| 39 | /*----------------------------------------------------------------------------*/ | ||
| 40 | |||
| 41 | #define SIZE_1KB 0x400 | ||
| 42 | |||
| 43 | /* | ||
| 44 | * Maximum number of shared memory blocks that can be reigsters in a connection | ||
| 45 | */ | ||
| 46 | #define TF_SHMEM_MAX_COUNT (64) | ||
| 47 | |||
| 48 | /* | ||
| 49 | * Describes the possible types of shared memories | ||
| 50 | * | ||
| 51 | * TF_SHMEM_TYPE_PREALLOC_REGISTERED_SHMEM : | ||
| 52 | * The descriptor describes a registered shared memory. | ||
| 53 | * Its coarse pages are preallocated when initializing the | ||
| 54 | * connection | ||
| 55 | * TF_SHMEM_TYPE_REGISTERED_SHMEM : | ||
| 56 | * The descriptor describes a registered shared memory. | ||
| 57 | * Its coarse pages are not preallocated | ||
| 58 | * TF_SHMEM_TYPE_PM_HIBERNATE : | ||
| 59 | * The descriptor describes a power management shared memory. | ||
| 60 | */ | ||
| 61 | enum TF_SHMEM_TYPE { | ||
| 62 | TF_SHMEM_TYPE_PREALLOC_REGISTERED_SHMEM = 0, | ||
| 63 | TF_SHMEM_TYPE_REGISTERED_SHMEM, | ||
| 64 | TF_SHMEM_TYPE_PM_HIBERNATE, | ||
| 65 | }; | ||
| 66 | |||
| 67 | |||
| 68 | /* | ||
| 69 | * This structure contains a pointer on a coarse page table | ||
| 70 | */ | ||
| 71 | struct tf_coarse_page_table { | ||
| 72 | /* | ||
| 73 | * Identifies the coarse page table descriptor in | ||
| 74 | * free_coarse_page_tables list | ||
| 75 | */ | ||
| 76 | struct list_head list; | ||
| 77 | |||
| 78 | /* | ||
| 79 | * The address of the coarse page table | ||
| 80 | */ | ||
| 81 | u32 *descriptors; | ||
| 82 | |||
| 83 | /* | ||
| 84 | * The address of the array containing this coarse page table | ||
| 85 | */ | ||
| 86 | struct tf_coarse_page_table_array *parent; | ||
| 87 | }; | ||
| 88 | |||
| 89 | |||
| 90 | #define TF_PAGE_DESCRIPTOR_TYPE_NORMAL 0 | ||
| 91 | #define TF_PAGE_DESCRIPTOR_TYPE_PREALLOCATED 1 | ||
| 92 | |||
| 93 | /* | ||
| 94 | * This structure describes an array of up to 4 coarse page tables | ||
| 95 | * allocated within a single 4KB page. | ||
| 96 | */ | ||
| 97 | struct tf_coarse_page_table_array { | ||
| 98 | /* | ||
| 99 | * identifies the element in the coarse_page_table_arrays list | ||
| 100 | */ | ||
| 101 | struct list_head list; | ||
| 102 | |||
| 103 | /* | ||
| 104 | * Type of page descriptor | ||
| 105 | * can take any of TF_PAGE_DESCRIPTOR_TYPE_XXX value | ||
| 106 | */ | ||
| 107 | u32 type; | ||
| 108 | |||
| 109 | struct tf_coarse_page_table coarse_page_tables[4]; | ||
| 110 | |||
| 111 | /* | ||
| 112 | * A counter of the number of coarse pages currently used | ||
| 113 | * the max value should be 4 (one coarse page table is 1KB while one | ||
| 114 | * page is 4KB) | ||
| 115 | */ | ||
| 116 | u8 ref_count; | ||
| 117 | }; | ||
| 118 | |||
| 119 | |||
| 120 | /* | ||
| 121 | * This structure describes a list of coarse page table arrays | ||
| 122 | * with some of the coarse page tables free. It is used | ||
| 123 | * when the driver needs to allocate a new coarse page | ||
| 124 | * table. | ||
| 125 | */ | ||
| 126 | struct tf_coarse_page_table_allocation_context { | ||
| 127 | /* | ||
| 128 | * The spin lock protecting concurrent access to the structure. | ||
| 129 | */ | ||
| 130 | spinlock_t lock; | ||
| 131 | |||
| 132 | /* | ||
| 133 | * The list of allocated coarse page table arrays | ||
| 134 | */ | ||
| 135 | struct list_head coarse_page_table_arrays; | ||
| 136 | |||
| 137 | /* | ||
| 138 | * The list of free coarse page tables | ||
| 139 | */ | ||
| 140 | struct list_head free_coarse_page_tables; | ||
| 141 | }; | ||
| 142 | |||
| 143 | |||
| 144 | /* | ||
| 145 | * Fully describes a shared memory block | ||
| 146 | */ | ||
| 147 | struct tf_shmem_desc { | ||
| 148 | /* | ||
| 149 | * Identifies the shared memory descriptor in the list of free shared | ||
| 150 | * memory descriptors | ||
| 151 | */ | ||
| 152 | struct list_head list; | ||
| 153 | |||
| 154 | /* | ||
| 155 | * Identifies the type of shared memory descriptor | ||
| 156 | */ | ||
| 157 | enum TF_SHMEM_TYPE type; | ||
| 158 | |||
| 159 | /* | ||
| 160 | * The identifier of the block of shared memory, as returned by the | ||
| 161 | * Secure World. | ||
| 162 | * This identifier is block field of a REGISTER_SHARED_MEMORY answer | ||
| 163 | */ | ||
| 164 | u32 block_identifier; | ||
| 165 | |||
| 166 | /* Client buffer */ | ||
| 167 | u8 *client_buffer; | ||
| 168 | |||
| 169 | /* Up to eight coarse page table context */ | ||
| 170 | struct tf_coarse_page_table *coarse_pg_table[TF_MAX_COARSE_PAGES]; | ||
| 171 | |||
| 172 | u32 coarse_pg_table_count; | ||
| 173 | |||
| 174 | /* Reference counter */ | ||
| 175 | atomic_t ref_count; | ||
| 176 | }; | ||
| 177 | |||
| 178 | |||
| 179 | /*----------------------------------------------------------------------------*/ | ||
| 180 | |||
| 181 | /* | ||
| 182 | * This structure describes the communication with the Secure World | ||
| 183 | * | ||
| 184 | * Note that this driver supports only one instance of the Secure World | ||
| 185 | */ | ||
| 186 | struct tf_comm { | ||
| 187 | /* | ||
| 188 | * The spin lock protecting concurrent access to the structure. | ||
| 189 | */ | ||
| 190 | spinlock_t lock; | ||
| 191 | |||
| 192 | /* | ||
| 193 | * Bit vector with the following possible flags: | ||
| 194 | * - TF_COMM_FLAG_IRQ_REQUESTED: If set, indicates that | ||
| 195 | * the IRQ has been successfuly requested. | ||
| 196 | * - TF_COMM_FLAG_TERMINATING: If set, indicates that the | ||
| 197 | * communication with the Secure World is being terminated. | ||
| 198 | * Transmissions to the Secure World are not permitted | ||
| 199 | * - TF_COMM_FLAG_W3B_ALLOCATED: If set, indicates that the | ||
| 200 | * W3B buffer has been allocated. | ||
| 201 | * | ||
| 202 | * This bit vector must be accessed with the kernel's atomic bitwise | ||
| 203 | * operations. | ||
| 204 | */ | ||
| 205 | unsigned long flags; | ||
| 206 | |||
| 207 | /* | ||
| 208 | * The virtual address of the L1 shared buffer. | ||
| 209 | */ | ||
| 210 | struct tf_l1_shared_buffer *l1_buffer; | ||
| 211 | |||
| 212 | /* | ||
| 213 | * The wait queue the client threads are waiting on. | ||
| 214 | */ | ||
| 215 | wait_queue_head_t wait_queue; | ||
| 216 | |||
| 217 | #ifdef CONFIG_TF_TRUSTZONE | ||
| 218 | /* | ||
| 219 | * The interrupt line used by the Secure World. | ||
| 220 | */ | ||
| 221 | int soft_int_irq; | ||
| 222 | |||
| 223 | /* ----- W3B ----- */ | ||
| 224 | /* shared memory descriptor to identify the W3B */ | ||
| 225 | struct tf_shmem_desc w3b_shmem_desc; | ||
| 226 | |||
| 227 | /* Virtual address of the kernel allocated shared memory */ | ||
| 228 | u32 w3b; | ||
| 229 | |||
| 230 | /* offset of data in shared memory coarse pages */ | ||
| 231 | u32 w3b_shmem_offset; | ||
| 232 | |||
| 233 | u32 w3b_shmem_size; | ||
| 234 | |||
| 235 | struct tf_coarse_page_table_allocation_context | ||
| 236 | w3b_cpt_alloc_context; | ||
| 237 | #endif | ||
| 238 | #ifdef CONFIG_TF_ZEBRA | ||
| 239 | /* | ||
| 240 | * The SE SDP can only be initialized once... | ||
| 241 | */ | ||
| 242 | int se_initialized; | ||
| 243 | |||
| 244 | /* | ||
| 245 | * Lock to be held by a client when executing an RPC | ||
| 246 | */ | ||
| 247 | struct mutex rpc_mutex; | ||
| 248 | |||
| 249 | /* | ||
| 250 | * Lock to protect concurrent accesses to DMA channels | ||
| 251 | */ | ||
| 252 | struct mutex dma_mutex; | ||
| 253 | #endif | ||
| 254 | }; | ||
| 255 | |||
| 256 | |||
| 257 | #define TF_COMM_FLAG_IRQ_REQUESTED (0) | ||
| 258 | #define TF_COMM_FLAG_PA_AVAILABLE (1) | ||
| 259 | #define TF_COMM_FLAG_TERMINATING (2) | ||
| 260 | #define TF_COMM_FLAG_W3B_ALLOCATED (3) | ||
| 261 | #define TF_COMM_FLAG_L1_SHARED_ALLOCATED (4) | ||
| 262 | |||
| 263 | /*----------------------------------------------------------------------------*/ | ||
| 264 | |||
| 265 | struct tf_device_stats { | ||
| 266 | atomic_t stat_pages_allocated; | ||
| 267 | atomic_t stat_memories_allocated; | ||
| 268 | atomic_t stat_pages_locked; | ||
| 269 | }; | ||
| 270 | |||
| 271 | /* | ||
| 272 | * This structure describes the information about one device handled by the | ||
| 273 | * driver. Note that the driver supports only a single device. see the global | ||
| 274 | * variable g_tf_dev | ||
| 275 | |||
| 276 | */ | ||
| 277 | struct tf_device { | ||
| 278 | /* | ||
| 279 | * The kernel object for the device | ||
| 280 | */ | ||
| 281 | struct kobject kobj; | ||
| 282 | |||
| 283 | /* | ||
| 284 | * The device number for the device. | ||
| 285 | */ | ||
| 286 | dev_t dev_number; | ||
| 287 | |||
| 288 | /* | ||
| 289 | * Interfaces the char device with the kernel. | ||
| 290 | */ | ||
| 291 | struct cdev cdev; | ||
| 292 | |||
| 293 | #ifdef CONFIG_TF_TEEC | ||
| 294 | struct cdev cdev_teec; | ||
| 295 | #endif | ||
| 296 | |||
| 297 | #ifdef CONFIG_TF_ZEBRA | ||
| 298 | struct cdev cdev_ctrl; | ||
| 299 | |||
| 300 | /* | ||
| 301 | * Globals for CUS | ||
| 302 | */ | ||
| 303 | /* Current key handles loaded in HWAs */ | ||
| 304 | u32 aes1_key_context; | ||
| 305 | u32 des_key_context; | ||
| 306 | bool sham1_is_public; | ||
| 307 | |||
| 308 | /* Object used to serialize HWA accesses */ | ||
| 309 | struct semaphore aes1_sema; | ||
| 310 | struct semaphore des_sema; | ||
| 311 | struct semaphore sha_sema; | ||
| 312 | |||
| 313 | /* | ||
| 314 | * An aligned and correctly shaped pre-allocated buffer used for DMA | ||
| 315 | * transfers | ||
| 316 | */ | ||
| 317 | u32 dma_buffer_length; | ||
| 318 | u8 *dma_buffer; | ||
| 319 | dma_addr_t dma_buffer_phys; | ||
| 320 | |||
| 321 | /* Workspace allocated at boot time and reserved to the Secure World */ | ||
| 322 | u32 workspace_addr; | ||
| 323 | u32 workspace_size; | ||
| 324 | |||
| 325 | /* | ||
| 326 | * A Mutex to provide exclusive locking of the ioctl() | ||
| 327 | */ | ||
| 328 | struct mutex dev_mutex; | ||
| 329 | #endif | ||
| 330 | |||
| 331 | /* | ||
| 332 | * Communications with the SM. | ||
| 333 | */ | ||
| 334 | struct tf_comm sm; | ||
| 335 | |||
| 336 | /* | ||
| 337 | * Lists the connections attached to this device. A connection is | ||
| 338 | * created each time a user space application "opens" a file descriptor | ||
| 339 | * on the driver | ||
| 340 | */ | ||
| 341 | struct list_head connection_list; | ||
| 342 | |||
| 343 | /* | ||
| 344 | * The spin lock used to protect concurrent access to the connection | ||
| 345 | * list. | ||
| 346 | */ | ||
| 347 | spinlock_t connection_list_lock; | ||
| 348 | |||
| 349 | struct tf_device_stats stats; | ||
| 350 | }; | ||
| 351 | |||
| 352 | /*----------------------------------------------------------------------------*/ | ||
| 353 | /* | ||
| 354 | * This type describes a connection state. | ||
| 355 | * This is used to determine whether a message is valid or not. | ||
| 356 | * | ||
| 357 | * Messages are only valid in a certain device state. | ||
| 358 | * Messages may be invalidated between the start of the ioctl call and the | ||
| 359 | * moment the message is sent to the Secure World. | ||
| 360 | * | ||
| 361 | * TF_CONN_STATE_NO_DEVICE_CONTEXT : | ||
| 362 | * The connection has no DEVICE_CONTEXT created and no | ||
| 363 | * CREATE_DEVICE_CONTEXT being processed by the Secure World | ||
| 364 | * TF_CONN_STATE_CREATE_DEVICE_CONTEXT_SENT : | ||
| 365 | * The connection has a CREATE_DEVICE_CONTEXT being processed by the Secure | ||
| 366 | * World | ||
| 367 | * TF_CONN_STATE_VALID_DEVICE_CONTEXT : | ||
| 368 | * The connection has a DEVICE_CONTEXT created and no | ||
| 369 | * DESTROY_DEVICE_CONTEXT is being processed by the Secure World | ||
| 370 | * TF_CONN_STATE_DESTROY_DEVICE_CONTEXT_SENT : | ||
| 371 | * The connection has a DESTROY_DEVICE_CONTEXT being processed by the Secure | ||
| 372 | * World | ||
| 373 | */ | ||
| 374 | enum TF_CONN_STATE { | ||
| 375 | TF_CONN_STATE_NO_DEVICE_CONTEXT = 0, | ||
| 376 | TF_CONN_STATE_CREATE_DEVICE_CONTEXT_SENT, | ||
| 377 | TF_CONN_STATE_VALID_DEVICE_CONTEXT, | ||
| 378 | TF_CONN_STATE_DESTROY_DEVICE_CONTEXT_SENT | ||
| 379 | }; | ||
| 380 | |||
| 381 | |||
| 382 | /* | ||
| 383 | * This type describes the status of the command. | ||
| 384 | * | ||
| 385 | * PENDING: | ||
| 386 | * The initial state; the command has not been sent yet. | ||
| 387 | * SENT: | ||
| 388 | * The command has been sent, we are waiting for an answer. | ||
| 389 | * ABORTED: | ||
| 390 | * The command cannot be sent because the device context is invalid. | ||
| 391 | * Note that this only covers the case where some other thread | ||
| 392 | * sent a DESTROY_DEVICE_CONTEXT command. | ||
| 393 | */ | ||
| 394 | enum TF_COMMAND_STATE { | ||
| 395 | TF_COMMAND_STATE_PENDING = 0, | ||
| 396 | TF_COMMAND_STATE_SENT, | ||
| 397 | TF_COMMAND_STATE_ABORTED | ||
| 398 | }; | ||
| 399 | |||
| 400 | /* | ||
| 401 | * The origin of connection parameters such as login data and | ||
| 402 | * memory reference pointers. | ||
| 403 | * | ||
| 404 | * PROCESS: the calling process. All arguments must be validated. | ||
| 405 | * KERNEL: kernel code. All arguments can be trusted by this driver. | ||
| 406 | */ | ||
| 407 | enum TF_CONNECTION_OWNER { | ||
| 408 | TF_CONNECTION_OWNER_PROCESS = 0, | ||
| 409 | TF_CONNECTION_OWNER_KERNEL, | ||
| 410 | }; | ||
| 411 | |||
| 412 | |||
| 413 | /* | ||
| 414 | * This structure describes a connection to the driver | ||
| 415 | * A connection is created each time an application opens a file descriptor on | ||
| 416 | * the driver | ||
| 417 | */ | ||
| 418 | struct tf_connection { | ||
| 419 | /* | ||
| 420 | * Identifies the connection in the list of the connections attached to | ||
| 421 | * the same device. | ||
| 422 | */ | ||
| 423 | struct list_head list; | ||
| 424 | |||
| 425 | /* | ||
| 426 | * State of the connection. | ||
| 427 | */ | ||
| 428 | enum TF_CONN_STATE state; | ||
| 429 | |||
| 430 | /* | ||
| 431 | * A pointer to the corresponding device structure | ||
| 432 | */ | ||
| 433 | struct tf_device *dev; | ||
| 434 | |||
| 435 | /* | ||
| 436 | * A spinlock to use to access state | ||
| 437 | */ | ||
| 438 | spinlock_t state_lock; | ||
| 439 | |||
| 440 | /* | ||
| 441 | * Counts the number of operations currently pending on the connection. | ||
| 442 | * (for debug only) | ||
| 443 | */ | ||
| 444 | atomic_t pending_op_count; | ||
| 445 | |||
| 446 | /* | ||
| 447 | * A handle for the device context | ||
| 448 | */ | ||
| 449 | u32 device_context; | ||
| 450 | |||
| 451 | /* | ||
| 452 | * Lists the used shared memory descriptors | ||
| 453 | */ | ||
| 454 | struct list_head used_shmem_list; | ||
| 455 | |||
| 456 | /* | ||
| 457 | * Lists the free shared memory descriptors | ||
| 458 | */ | ||
| 459 | struct list_head free_shmem_list; | ||
| 460 | |||
| 461 | /* | ||
| 462 | * A mutex to use to access this structure | ||
| 463 | */ | ||
| 464 | struct mutex shmem_mutex; | ||
| 465 | |||
| 466 | /* | ||
| 467 | * Counts the number of shared memories registered. | ||
| 468 | */ | ||
| 469 | atomic_t shmem_count; | ||
| 470 | |||
| 471 | /* | ||
| 472 | * Page to retrieve memory properties when | ||
| 473 | * registering shared memory through REGISTER_SHARED_MEMORY | ||
| 474 | * messages | ||
| 475 | */ | ||
| 476 | struct vm_area_struct **vmas; | ||
| 477 | |||
| 478 | /* | ||
| 479 | * coarse page table allocation context | ||
| 480 | */ | ||
| 481 | struct tf_coarse_page_table_allocation_context cpt_alloc_context; | ||
| 482 | |||
| 483 | /* The origin of connection parameters such as login data and | ||
| 484 | memory reference pointers. */ | ||
| 485 | enum TF_CONNECTION_OWNER owner; | ||
| 486 | |||
| 487 | #ifdef CONFIG_TF_ZEBRA | ||
| 488 | /* Lists all the Cryptoki Update Shortcuts */ | ||
| 489 | struct list_head shortcut_list; | ||
| 490 | |||
| 491 | /* Lock to protect concurrent accesses to shortcut_list */ | ||
| 492 | spinlock_t shortcut_list_lock; | ||
| 493 | #endif | ||
| 494 | }; | ||
| 495 | |||
| 496 | /*----------------------------------------------------------------------------*/ | ||
| 497 | |||
| 498 | /* | ||
| 499 | * The operation_id field of a message points to this structure. | ||
| 500 | * It is used to identify the thread that triggered the message transmission | ||
| 501 | * Whoever reads an answer can wake up that thread using the completion event | ||
| 502 | */ | ||
| 503 | struct tf_answer_struct { | ||
| 504 | bool answer_copied; | ||
| 505 | union tf_answer *answer; | ||
| 506 | }; | ||
| 507 | |||
| 508 | /*----------------------------------------------------------------------------*/ | ||
| 509 | |||
| 510 | /** | ||
| 511 | * The ASCII-C string representation of the base name of the devices managed by | ||
| 512 | * this driver. | ||
| 513 | */ | ||
| 514 | #define TF_DEVICE_BASE_NAME "tf_driver" | ||
| 515 | |||
| 516 | |||
| 517 | /** | ||
| 518 | * The major and minor numbers of the registered character device driver. | ||
| 519 | * Only 1 instance of the driver is supported. | ||
| 520 | */ | ||
| 521 | #define TF_DEVICE_MINOR_NUMBER (0) | ||
| 522 | |||
| 523 | struct tf_device *tf_get_device(void); | ||
| 524 | |||
| 525 | #define CLEAN_CACHE_CFG_MASK (~0xC) /* 1111 0011 */ | ||
| 526 | |||
| 527 | /*----------------------------------------------------------------------------*/ | ||
| 528 | /* | ||
| 529 | * Kernel Differences | ||
| 530 | */ | ||
| 531 | |||
| 532 | #ifdef CONFIG_ANDROID | ||
| 533 | #define GROUP_INFO get_current_groups() | ||
| 534 | #else | ||
| 535 | #define GROUP_INFO (current->group_info) | ||
| 536 | #endif | ||
| 537 | |||
| 538 | #endif /* !defined(__TF_DEFS_H__) */ | ||
diff --git a/security/tf_driver/tf_device.c b/security/tf_driver/tf_device.c new file mode 100644 index 00000000000..ad44b46c206 --- /dev/null +++ b/security/tf_driver/tf_device.c | |||
| @@ -0,0 +1,796 @@ | |||
| 1 | /** | ||
| 2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 17 | * MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/atomic.h> | ||
| 21 | #include <linux/uaccess.h> | ||
| 22 | #include <linux/module.h> | ||
| 23 | #include <linux/errno.h> | ||
| 24 | #include <linux/mm.h> | ||
| 25 | #include <linux/page-flags.h> | ||
| 26 | #include <linux/pm.h> | ||
| 27 | #include <linux/syscore_ops.h> | ||
| 28 | #include <linux/vmalloc.h> | ||
| 29 | #include <linux/signal.h> | ||
| 30 | #ifdef CONFIG_ANDROID | ||
| 31 | #include <linux/device.h> | ||
| 32 | #endif | ||
| 33 | |||
| 34 | #include "tf_protocol.h" | ||
| 35 | #include "tf_defs.h" | ||
| 36 | #include "tf_util.h" | ||
| 37 | #include "tf_conn.h" | ||
| 38 | #include "tf_comm.h" | ||
| 39 | #ifdef CONFIG_TF_ZEBRA | ||
| 40 | #include <plat/cpu.h> | ||
| 41 | #include "tf_zebra.h" | ||
| 42 | #endif | ||
| 43 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
| 44 | #include "tf_crypto.h" | ||
| 45 | #endif | ||
| 46 | |||
| 47 | #include "s_version.h" | ||
| 48 | |||
| 49 | /*---------------------------------------------------------------------------- | ||
| 50 | * Forward Declarations | ||
| 51 | *----------------------------------------------------------------------------*/ | ||
| 52 | |||
| 53 | /* | ||
| 54 | * Creates and registers the device to be managed by the specified driver. | ||
| 55 | * | ||
| 56 | * Returns zero upon successful completion, or an appropriate error code upon | ||
| 57 | * failure. | ||
| 58 | */ | ||
| 59 | static int tf_device_register(void); | ||
| 60 | |||
| 61 | |||
| 62 | /* | ||
| 63 | * Implements the device Open callback. | ||
| 64 | */ | ||
| 65 | static int tf_device_open( | ||
| 66 | struct inode *inode, | ||
| 67 | struct file *file); | ||
| 68 | |||
| 69 | |||
| 70 | /* | ||
| 71 | * Implements the device Release callback. | ||
| 72 | */ | ||
| 73 | static int tf_device_release( | ||
| 74 | struct inode *inode, | ||
| 75 | struct file *file); | ||
| 76 | |||
| 77 | |||
| 78 | /* | ||
| 79 | * Implements the device ioctl callback. | ||
| 80 | */ | ||
| 81 | static long tf_device_ioctl( | ||
| 82 | struct file *file, | ||
| 83 | unsigned int ioctl_num, | ||
| 84 | unsigned long ioctl_param); | ||
| 85 | |||
| 86 | |||
| 87 | /* | ||
| 88 | * Implements the device shutdown callback. | ||
| 89 | */ | ||
| 90 | static int tf_device_shutdown(void); | ||
| 91 | |||
| 92 | |||
| 93 | /* | ||
| 94 | * Implements the device suspend callback. | ||
| 95 | */ | ||
| 96 | static int tf_device_suspend(void); | ||
| 97 | |||
| 98 | |||
| 99 | /* | ||
| 100 | * Implements the device resume callback. | ||
| 101 | */ | ||
| 102 | static int tf_device_resume(void); | ||
| 103 | |||
| 104 | |||
| 105 | /*--------------------------------------------------------------------------- | ||
| 106 | * Module Parameters | ||
| 107 | *---------------------------------------------------------------------------*/ | ||
| 108 | |||
| 109 | /* | ||
| 110 | * The device major number used to register a unique character device driver. | ||
| 111 | * Let the default value be 122 | ||
| 112 | */ | ||
| 113 | static int device_major_number = 122; | ||
| 114 | |||
| 115 | module_param(device_major_number, int, 0000); | ||
| 116 | MODULE_PARM_DESC(device_major_number, | ||
| 117 | "The device major number used to register a unique character " | ||
| 118 | "device driver"); | ||
| 119 | |||
| 120 | #ifdef CONFIG_TF_TRUSTZONE | ||
| 121 | /** | ||
| 122 | * The softint interrupt line used by the Secure World. | ||
| 123 | */ | ||
| 124 | static int soft_interrupt = -1; | ||
| 125 | |||
| 126 | module_param(soft_interrupt, int, 0000); | ||
| 127 | MODULE_PARM_DESC(soft_interrupt, | ||
| 128 | "The softint interrupt line used by the Secure world"); | ||
| 129 | #endif | ||
| 130 | |||
| 131 | #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT | ||
| 132 | unsigned tf_debug_level = UINT_MAX; | ||
| 133 | module_param_named(debug, tf_debug_level, uint, 0644); | ||
| 134 | #endif | ||
| 135 | |||
| 136 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
| 137 | char *tf_integrity_hmac_sha256_expected_value; | ||
| 138 | module_param_named(hmac_sha256, tf_integrity_hmac_sha256_expected_value, | ||
| 139 | charp, 0444); | ||
| 140 | |||
| 141 | #ifdef CONFIG_TF_DRIVER_FAULT_INJECTION | ||
| 142 | unsigned tf_fault_injection_mask; | ||
| 143 | module_param_named(fault, tf_fault_injection_mask, uint, 0644); | ||
| 144 | #endif | ||
| 145 | |||
| 146 | int tf_self_test_blkcipher_align; | ||
| 147 | module_param_named(post_align, tf_self_test_blkcipher_align, int, 0644); | ||
| 148 | int tf_self_test_blkcipher_use_vmalloc; | ||
| 149 | module_param_named(post_vmalloc, tf_self_test_blkcipher_use_vmalloc, int, 0644); | ||
| 150 | #endif | ||
| 151 | |||
| 152 | #ifdef CONFIG_ANDROID | ||
| 153 | static struct class *tf_class; | ||
| 154 | #endif | ||
| 155 | |||
| 156 | /*---------------------------------------------------------------------------- | ||
| 157 | * Global Variables | ||
| 158 | *----------------------------------------------------------------------------*/ | ||
| 159 | |||
| 160 | /* | ||
| 161 | * tf_driver character device definitions. | ||
| 162 | * read and write methods are not defined | ||
| 163 | * and will return an error if used by user space | ||
| 164 | */ | ||
| 165 | static const struct file_operations g_tf_device_file_ops = { | ||
| 166 | .owner = THIS_MODULE, | ||
| 167 | .open = tf_device_open, | ||
| 168 | .release = tf_device_release, | ||
| 169 | .unlocked_ioctl = tf_device_ioctl, | ||
| 170 | .llseek = no_llseek, | ||
| 171 | }; | ||
| 172 | |||
| 173 | |||
| 174 | static struct syscore_ops g_tf_device_syscore_ops = { | ||
| 175 | .shutdown = tf_device_shutdown, | ||
| 176 | .suspend = tf_device_suspend, | ||
| 177 | .resume = tf_device_resume, | ||
| 178 | }; | ||
| 179 | |||
| 180 | /* The single device supported by this driver */ | ||
| 181 | static struct tf_device g_tf_dev; | ||
| 182 | |||
| 183 | /*---------------------------------------------------------------------------- | ||
| 184 | * Implementations | ||
| 185 | *----------------------------------------------------------------------------*/ | ||
| 186 | |||
| 187 | struct tf_device *tf_get_device(void) | ||
| 188 | { | ||
| 189 | return &g_tf_dev; | ||
| 190 | } | ||
| 191 | |||
| 192 | /* | ||
| 193 | * sysfs entries | ||
| 194 | */ | ||
| 195 | struct tf_sysfs_entry { | ||
| 196 | struct attribute attr; | ||
| 197 | ssize_t (*show)(struct tf_device *, char *); | ||
| 198 | ssize_t (*store)(struct tf_device *, const char *, size_t); | ||
| 199 | }; | ||
| 200 | |||
| 201 | /* | ||
| 202 | * sysfs entry showing allocation stats | ||
| 203 | */ | ||
| 204 | static ssize_t info_show(struct tf_device *dev, char *buf) | ||
| 205 | { | ||
| 206 | struct tf_device_stats *dev_stats = &dev->stats; | ||
| 207 | |||
| 208 | return snprintf(buf, PAGE_SIZE, | ||
| 209 | "stat.memories.allocated: %d\n" | ||
| 210 | "stat.pages.allocated: %d\n" | ||
| 211 | "stat.pages.locked: %d\n", | ||
| 212 | atomic_read(&dev_stats->stat_memories_allocated), | ||
| 213 | atomic_read(&dev_stats->stat_pages_allocated), | ||
| 214 | atomic_read(&dev_stats->stat_pages_locked)); | ||
| 215 | } | ||
| 216 | static struct tf_sysfs_entry tf_info_entry = __ATTR_RO(info); | ||
| 217 | |||
| 218 | #ifdef CONFIG_TF_ZEBRA | ||
| 219 | /* | ||
| 220 | * sysfs entry showing whether secure world is up and running | ||
| 221 | */ | ||
| 222 | static ssize_t tf_started_show(struct tf_device *dev, char *buf) | ||
| 223 | { | ||
| 224 | int tf_started = test_bit(TF_COMM_FLAG_PA_AVAILABLE, | ||
| 225 | &dev->sm.flags); | ||
| 226 | |||
| 227 | return snprintf(buf, PAGE_SIZE, "%s\n", tf_started ? "yes" : "no"); | ||
| 228 | } | ||
| 229 | static struct tf_sysfs_entry tf_started_entry = | ||
| 230 | __ATTR_RO(tf_started); | ||
| 231 | |||
| 232 | static ssize_t workspace_addr_show(struct tf_device *dev, char *buf) | ||
| 233 | { | ||
| 234 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", dev->workspace_addr); | ||
| 235 | } | ||
| 236 | static struct tf_sysfs_entry tf_workspace_addr_entry = | ||
| 237 | __ATTR_RO(workspace_addr); | ||
| 238 | |||
| 239 | static ssize_t workspace_size_show(struct tf_device *dev, char *buf) | ||
| 240 | { | ||
| 241 | return snprintf(buf, PAGE_SIZE, "0x%08x\n", dev->workspace_size); | ||
| 242 | } | ||
| 243 | static struct tf_sysfs_entry tf_workspace_size_entry = | ||
| 244 | __ATTR_RO(workspace_size); | ||
| 245 | #endif | ||
| 246 | |||
| 247 | static ssize_t tf_attr_show(struct kobject *kobj, struct attribute *attr, | ||
| 248 | char *page) | ||
| 249 | { | ||
| 250 | struct tf_sysfs_entry *entry = container_of(attr, struct tf_sysfs_entry, | ||
| 251 | attr); | ||
| 252 | struct tf_device *dev = container_of(kobj, struct tf_device, kobj); | ||
| 253 | |||
| 254 | if (!entry->show) | ||
| 255 | return -EIO; | ||
| 256 | |||
| 257 | return entry->show(dev, page); | ||
| 258 | } | ||
| 259 | |||
| 260 | static ssize_t tf_attr_store(struct kobject *kobj, struct attribute *attr, | ||
| 261 | const char *page, size_t length) | ||
| 262 | { | ||
| 263 | struct tf_sysfs_entry *entry = container_of(attr, struct tf_sysfs_entry, | ||
| 264 | attr); | ||
| 265 | struct tf_device *dev = container_of(kobj, struct tf_device, kobj); | ||
| 266 | |||
| 267 | if (!entry->store) | ||
| 268 | return -EIO; | ||
| 269 | |||
| 270 | return entry->store(dev, page, length); | ||
| 271 | } | ||
| 272 | |||
| 273 | static void tf_kobj_release(struct kobject *kobj) {} | ||
| 274 | |||
| 275 | static struct attribute *tf_default_attrs[] = { | ||
| 276 | &tf_info_entry.attr, | ||
| 277 | #ifdef CONFIG_TF_ZEBRA | ||
| 278 | &tf_started_entry.attr, | ||
| 279 | &tf_workspace_addr_entry.attr, | ||
| 280 | &tf_workspace_size_entry.attr, | ||
| 281 | #endif | ||
| 282 | NULL, | ||
| 283 | }; | ||
| 284 | static const struct sysfs_ops tf_sysfs_ops = { | ||
| 285 | .show = tf_attr_show, | ||
| 286 | .store = tf_attr_store, | ||
| 287 | }; | ||
| 288 | static struct kobj_type tf_ktype = { | ||
| 289 | .release = tf_kobj_release, | ||
| 290 | .sysfs_ops = &tf_sysfs_ops, | ||
| 291 | .default_attrs = tf_default_attrs | ||
| 292 | }; | ||
| 293 | |||
| 294 | /*----------------------------------------------------------------------------*/ | ||
| 295 | |||
| 296 | #if defined(MODULE) && defined(CONFIG_TF_ZEBRA) | ||
| 297 | static char *smc_mem; | ||
| 298 | module_param(smc_mem, charp, S_IRUGO); | ||
| 299 | #endif | ||
| 300 | |||
| 301 | /* | ||
| 302 | * First routine called when the kernel module is loaded | ||
| 303 | */ | ||
| 304 | static int __init tf_device_register(void) | ||
| 305 | { | ||
| 306 | int error; | ||
| 307 | struct tf_device *dev = &g_tf_dev; | ||
| 308 | |||
| 309 | dprintk(KERN_INFO "tf_device_register()\n"); | ||
| 310 | |||
| 311 | /* | ||
| 312 | * Initialize the device | ||
| 313 | */ | ||
| 314 | dev->dev_number = MKDEV(device_major_number, | ||
| 315 | TF_DEVICE_MINOR_NUMBER); | ||
| 316 | cdev_init(&dev->cdev, &g_tf_device_file_ops); | ||
| 317 | dev->cdev.owner = THIS_MODULE; | ||
| 318 | |||
| 319 | INIT_LIST_HEAD(&dev->connection_list); | ||
| 320 | spin_lock_init(&dev->connection_list_lock); | ||
| 321 | |||
| 322 | #if defined(MODULE) && defined(CONFIG_TF_ZEBRA) | ||
| 323 | error = (*tf_comm_early_init)(); | ||
| 324 | if (error) | ||
| 325 | goto module_early_init_failed; | ||
| 326 | |||
| 327 | error = tf_device_mshield_init(smc_mem); | ||
| 328 | if (error) | ||
| 329 | goto mshield_init_failed; | ||
| 330 | |||
| 331 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
| 332 | error = tf_crypto_hmac_module_init(); | ||
| 333 | if (error) | ||
| 334 | goto hmac_init_failed; | ||
| 335 | |||
| 336 | error = tf_self_test_register_device(); | ||
| 337 | if (error) | ||
| 338 | goto self_test_register_device_failed; | ||
| 339 | #endif | ||
| 340 | #endif | ||
| 341 | |||
| 342 | /* register the sysfs object driver stats */ | ||
| 343 | error = kobject_init_and_add(&dev->kobj, &tf_ktype, NULL, "%s", | ||
| 344 | TF_DEVICE_BASE_NAME); | ||
| 345 | if (error) { | ||
| 346 | printk(KERN_ERR "tf_device_register(): " | ||
| 347 | "kobject_init_and_add failed (error %d)!\n", error); | ||
| 348 | kobject_put(&dev->kobj); | ||
| 349 | goto kobject_init_and_add_failed; | ||
| 350 | } | ||
| 351 | |||
| 352 | /* | ||
| 353 | * Register the system device. | ||
| 354 | */ | ||
| 355 | register_syscore_ops(&g_tf_device_syscore_ops); | ||
| 356 | |||
| 357 | /* | ||
| 358 | * Register the char device. | ||
| 359 | */ | ||
| 360 | printk(KERN_INFO "Registering char device %s (%u:%u)\n", | ||
| 361 | TF_DEVICE_BASE_NAME, | ||
| 362 | MAJOR(dev->dev_number), | ||
| 363 | MINOR(dev->dev_number)); | ||
| 364 | error = register_chrdev_region(dev->dev_number, 1, | ||
| 365 | TF_DEVICE_BASE_NAME); | ||
| 366 | if (error != 0) { | ||
| 367 | printk(KERN_ERR "tf_device_register():" | ||
| 368 | " register_chrdev_region failed (error %d)!\n", | ||
| 369 | error); | ||
| 370 | goto register_chrdev_region_failed; | ||
| 371 | } | ||
| 372 | |||
| 373 | error = cdev_add(&dev->cdev, dev->dev_number, 1); | ||
| 374 | if (error != 0) { | ||
| 375 | printk(KERN_ERR "tf_device_register(): " | ||
| 376 | "cdev_add failed (error %d)!\n", | ||
| 377 | error); | ||
| 378 | goto cdev_add_failed; | ||
| 379 | } | ||
| 380 | |||
| 381 | /* | ||
| 382 | * Initialize the communication with the Secure World. | ||
| 383 | */ | ||
| 384 | #ifdef CONFIG_TF_TRUSTZONE | ||
| 385 | dev->sm.soft_int_irq = soft_interrupt; | ||
| 386 | #endif | ||
| 387 | error = tf_init(&g_tf_dev.sm); | ||
| 388 | if (error != S_SUCCESS) { | ||
| 389 | dprintk(KERN_ERR "tf_device_register(): " | ||
| 390 | "tf_init failed (error %d)!\n", | ||
| 391 | error); | ||
| 392 | goto init_failed; | ||
| 393 | } | ||
| 394 | |||
| 395 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
| 396 | error = tf_self_test_post_init(&(dev_stats->kobj)); | ||
| 397 | /* N.B. error > 0 indicates a POST failure, which will not | ||
| 398 | prevent the module from loading. */ | ||
| 399 | if (error < 0) { | ||
| 400 | dprintk(KERN_ERR "tf_device_register(): " | ||
| 401 | "tf_self_test_post_vectors failed (error %d)!\n", | ||
| 402 | error); | ||
| 403 | goto post_failed; | ||
| 404 | } | ||
| 405 | #endif | ||
| 406 | |||
| 407 | #ifdef CONFIG_ANDROID | ||
| 408 | tf_class = class_create(THIS_MODULE, TF_DEVICE_BASE_NAME); | ||
| 409 | device_create(tf_class, NULL, | ||
| 410 | dev->dev_number, | ||
| 411 | NULL, TF_DEVICE_BASE_NAME); | ||
| 412 | #endif | ||
| 413 | |||
| 414 | #ifdef CONFIG_TF_ZEBRA | ||
| 415 | /* | ||
| 416 | * Initializes the /dev/tf_ctrl device node. | ||
| 417 | */ | ||
| 418 | error = tf_ctrl_device_register(); | ||
| 419 | if (error) | ||
| 420 | goto ctrl_failed; | ||
| 421 | #endif | ||
| 422 | |||
| 423 | #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT | ||
| 424 | address_cache_property((unsigned long) &tf_device_register); | ||
| 425 | #endif | ||
| 426 | /* | ||
| 427 | * Successful completion. | ||
| 428 | */ | ||
| 429 | |||
| 430 | dprintk(KERN_INFO "tf_device_register(): Success\n"); | ||
| 431 | return 0; | ||
| 432 | |||
| 433 | /* | ||
| 434 | * Error: undo all operations in the reverse order | ||
| 435 | */ | ||
| 436 | #ifdef CONFIG_TF_ZEBRA | ||
| 437 | ctrl_failed: | ||
| 438 | #endif | ||
| 439 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
| 440 | tf_self_test_post_exit(); | ||
| 441 | post_failed: | ||
| 442 | #endif | ||
| 443 | init_failed: | ||
| 444 | cdev_del(&dev->cdev); | ||
| 445 | cdev_add_failed: | ||
| 446 | unregister_chrdev_region(dev->dev_number, 1); | ||
| 447 | register_chrdev_region_failed: | ||
| 448 | unregister_syscore_ops(&g_tf_device_syscore_ops); | ||
| 449 | kobject_init_and_add_failed: | ||
| 450 | kobject_del(&g_tf_dev.kobj); | ||
| 451 | |||
| 452 | #if defined(MODULE) && defined(CONFIG_TF_ZEBRA) | ||
| 453 | #ifdef CONFIG_TF_DRIVER_CRYPTO_FIPS | ||
| 454 | tf_self_test_unregister_device(); | ||
| 455 | self_test_register_device_failed: | ||
| 456 | tf_crypto_hmac_module_exit(); | ||
| 457 | hmac_init_failed: | ||
| 458 | #endif | ||
| 459 | tf_device_mshield_exit(); | ||
| 460 | mshield_init_failed: | ||
| 461 | module_early_init_failed: | ||
| 462 | #endif | ||
| 463 | dprintk(KERN_INFO "tf_device_register(): Failure (error %d)\n", | ||
| 464 | error); | ||
| 465 | return error; | ||
| 466 | } | ||
| 467 | |||
| 468 | /*----------------------------------------------------------------------------*/ | ||
| 469 | |||
| 470 | static int tf_device_open(struct inode *inode, struct file *file) | ||
| 471 | { | ||
| 472 | int error; | ||
| 473 | struct tf_device *dev = &g_tf_dev; | ||
| 474 | struct tf_connection *connection = NULL; | ||
| 475 | |||
| 476 | dprintk(KERN_INFO "tf_device_open(%u:%u, %p)\n", | ||
| 477 | imajor(inode), iminor(inode), file); | ||
| 478 | |||
| 479 | /* Dummy lseek for non-seekable driver */ | ||
| 480 | error = nonseekable_open(inode, file); | ||
| 481 | if (error != 0) { | ||
| 482 | dprintk(KERN_ERR "tf_device_open(%p): " | ||
| 483 | "nonseekable_open failed (error %d)!\n", | ||
| 484 | file, error); | ||
| 485 | goto error; | ||
| 486 | } | ||
| 487 | |||
| 488 | #ifndef CONFIG_ANDROID | ||
| 489 | /* | ||
| 490 | * Check file flags. We only autthorize the O_RDWR access | ||
| 491 | */ | ||
| 492 | if (file->f_flags != O_RDWR) { | ||
| 493 | dprintk(KERN_ERR "tf_device_open(%p): " | ||
| 494 | "Invalid access mode %u\n", | ||
| 495 | file, file->f_flags); | ||
| 496 | error = -EACCES; | ||
| 497 | goto error; | ||
| 498 | } | ||
| 499 | #endif | ||
| 500 | |||
| 501 | /* | ||
| 502 | * Open a new connection. | ||
| 503 | */ | ||
| 504 | |||
| 505 | error = tf_open(dev, file, &connection); | ||
| 506 | if (error != 0) { | ||
| 507 | dprintk(KERN_ERR "tf_device_open(%p): " | ||
| 508 | "tf_open failed (error %d)!\n", | ||
| 509 | file, error); | ||
| 510 | goto error; | ||
| 511 | } | ||
| 512 | |||
| 513 | file->private_data = connection; | ||
| 514 | |||
| 515 | /* | ||
| 516 | * Send the CreateDeviceContext command to the secure | ||
| 517 | */ | ||
| 518 | error = tf_create_device_context(connection); | ||
| 519 | if (error != 0) { | ||
| 520 | dprintk(KERN_ERR "tf_device_open(%p): " | ||
| 521 | "tf_create_device_context failed (error %d)!\n", | ||
| 522 | file, error); | ||
| 523 | goto error1; | ||
| 524 | } | ||
| 525 | |||
| 526 | /* | ||
| 527 | * Successful completion. | ||
| 528 | */ | ||
| 529 | |||
| 530 | dprintk(KERN_INFO "tf_device_open(%p): Success (connection=%p)\n", | ||
| 531 | file, connection); | ||
| 532 | return 0; | ||
| 533 | |||
| 534 | /* | ||
| 535 | * Error handling. | ||
| 536 | */ | ||
| 537 | |||
| 538 | error1: | ||
| 539 | tf_close(connection); | ||
| 540 | error: | ||
| 541 | dprintk(KERN_INFO "tf_device_open(%p): Failure (error %d)\n", | ||
| 542 | file, error); | ||
| 543 | return error; | ||
| 544 | } | ||
| 545 | |||
| 546 | /*----------------------------------------------------------------------------*/ | ||
| 547 | |||
| 548 | static int tf_device_release(struct inode *inode, struct file *file) | ||
| 549 | { | ||
| 550 | struct tf_connection *connection; | ||
| 551 | |||
| 552 | dprintk(KERN_INFO "tf_device_release(%u:%u, %p)\n", | ||
| 553 | imajor(inode), iminor(inode), file); | ||
| 554 | |||
| 555 | connection = tf_conn_from_file(file); | ||
| 556 | tf_close(connection); | ||
| 557 | |||
| 558 | dprintk(KERN_INFO "tf_device_release(%p): Success\n", file); | ||
| 559 | return 0; | ||
| 560 | } | ||
| 561 | |||
| 562 | /*----------------------------------------------------------------------------*/ | ||
| 563 | |||
| 564 | static long tf_device_ioctl(struct file *file, unsigned int ioctl_num, | ||
| 565 | unsigned long ioctl_param) | ||
| 566 | { | ||
| 567 | int result = S_SUCCESS; | ||
| 568 | struct tf_connection *connection; | ||
| 569 | union tf_command command; | ||
| 570 | struct tf_command_header header; | ||
| 571 | union tf_answer answer; | ||
| 572 | u32 command_size; | ||
| 573 | u32 answer_size; | ||
| 574 | void *user_answer; | ||
| 575 | |||
| 576 | dprintk(KERN_INFO "tf_device_ioctl(%p, %u, %p)\n", | ||
| 577 | file, ioctl_num, (void *) ioctl_param); | ||
| 578 | |||
| 579 | switch (ioctl_num) { | ||
| 580 | case IOCTL_TF_GET_VERSION: | ||
| 581 | /* ioctl is asking for the driver interface version */ | ||
| 582 | result = TF_DRIVER_INTERFACE_VERSION; | ||
| 583 | goto exit; | ||
| 584 | |||
| 585 | case IOCTL_TF_EXCHANGE: | ||
| 586 | /* | ||
| 587 | * ioctl is asking to perform a message exchange with the Secure | ||
| 588 | * Module | ||
| 589 | */ | ||
| 590 | |||
| 591 | /* | ||
| 592 | * Make a local copy of the data from the user application | ||
| 593 | * This routine checks the data is readable | ||
| 594 | * | ||
| 595 | * Get the header first. | ||
| 596 | */ | ||
| 597 | if (copy_from_user(&header, | ||
| 598 | (struct tf_command_header *)ioctl_param, | ||
| 599 | sizeof(struct tf_command_header))) { | ||
| 600 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
| 601 | "Cannot access ioctl parameter %p\n", | ||
| 602 | file, (void *) ioctl_param); | ||
| 603 | result = -EFAULT; | ||
| 604 | goto exit; | ||
| 605 | } | ||
| 606 | |||
| 607 | /* size in words of u32 */ | ||
| 608 | command_size = header.message_size + | ||
| 609 | sizeof(struct tf_command_header)/sizeof(u32); | ||
| 610 | if (command_size > sizeof(command)/sizeof(u32)) { | ||
| 611 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
| 612 | "Buffer overflow: too many bytes to copy %d\n", | ||
| 613 | file, command_size); | ||
| 614 | result = -EFAULT; | ||
| 615 | goto exit; | ||
| 616 | } | ||
| 617 | |||
| 618 | if (copy_from_user(&command, | ||
| 619 | (union tf_command *)ioctl_param, | ||
| 620 | command_size * sizeof(u32))) { | ||
| 621 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
| 622 | "Cannot access ioctl parameter %p\n", | ||
| 623 | file, (void *) ioctl_param); | ||
| 624 | result = -EFAULT; | ||
| 625 | goto exit; | ||
| 626 | } | ||
| 627 | |||
| 628 | connection = tf_conn_from_file(file); | ||
| 629 | BUG_ON(connection == NULL); | ||
| 630 | |||
| 631 | /* | ||
| 632 | * The answer memory space address is in the operation_id field | ||
| 633 | */ | ||
| 634 | user_answer = (void *) command.header.operation_id; | ||
| 635 | |||
| 636 | atomic_inc(&(connection->pending_op_count)); | ||
| 637 | |||
| 638 | dprintk(KERN_WARNING "tf_device_ioctl(%p): " | ||
| 639 | "Sending message type 0x%08x\n", | ||
| 640 | file, command.header.message_type); | ||
| 641 | |||
| 642 | switch (command.header.message_type) { | ||
| 643 | case TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION: | ||
| 644 | result = tf_open_client_session(connection, | ||
| 645 | &command, &answer); | ||
| 646 | break; | ||
| 647 | |||
| 648 | case TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION: | ||
| 649 | result = tf_close_client_session(connection, | ||
| 650 | &command, &answer); | ||
| 651 | break; | ||
| 652 | |||
| 653 | case TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY: | ||
| 654 | result = tf_register_shared_memory(connection, | ||
| 655 | &command, &answer); | ||
| 656 | break; | ||
| 657 | |||
| 658 | case TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY: | ||
| 659 | result = tf_release_shared_memory(connection, | ||
| 660 | &command, &answer); | ||
| 661 | break; | ||
| 662 | |||
| 663 | case TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND: | ||
| 664 | result = tf_invoke_client_command(connection, | ||
| 665 | &command, &answer); | ||
| 666 | break; | ||
| 667 | |||
| 668 | case TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND: | ||
| 669 | result = tf_cancel_client_command(connection, | ||
| 670 | &command, &answer); | ||
| 671 | break; | ||
| 672 | |||
| 673 | default: | ||
| 674 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
| 675 | "Incorrect message type (0x%08x)!\n", | ||
| 676 | connection, command.header.message_type); | ||
| 677 | result = -EOPNOTSUPP; | ||
| 678 | break; | ||
| 679 | } | ||
| 680 | |||
| 681 | atomic_dec(&(connection->pending_op_count)); | ||
| 682 | |||
| 683 | if (result != 0) { | ||
| 684 | dprintk(KERN_WARNING "tf_device_ioctl(%p): " | ||
| 685 | "Operation returning error code 0x%08x)!\n", | ||
| 686 | file, result); | ||
| 687 | goto exit; | ||
| 688 | } | ||
| 689 | |||
| 690 | /* | ||
| 691 | * Copy the answer back to the user space application. | ||
| 692 | * The driver does not check this field, only copy back to user | ||
| 693 | * space the data handed over by Secure World | ||
| 694 | */ | ||
| 695 | answer_size = answer.header.message_size + | ||
| 696 | sizeof(struct tf_answer_header)/sizeof(u32); | ||
| 697 | if (copy_to_user(user_answer, | ||
| 698 | &answer, answer_size * sizeof(u32))) { | ||
| 699 | dprintk(KERN_WARNING "tf_device_ioctl(%p): " | ||
| 700 | "Failed to copy back the full command " | ||
| 701 | "answer to %p\n", file, user_answer); | ||
| 702 | result = -EFAULT; | ||
| 703 | goto exit; | ||
| 704 | } | ||
| 705 | |||
| 706 | /* successful completion */ | ||
| 707 | dprintk(KERN_INFO "tf_device_ioctl(%p): Success\n", file); | ||
| 708 | break; | ||
| 709 | |||
| 710 | case IOCTL_TF_GET_DESCRIPTION: { | ||
| 711 | /* ioctl asking for the version information buffer */ | ||
| 712 | struct tf_version_information_buffer *pInfoBuffer; | ||
| 713 | |||
| 714 | dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION:(%p, %u, %p)\n", | ||
| 715 | file, ioctl_num, (void *) ioctl_param); | ||
| 716 | |||
| 717 | pInfoBuffer = | ||
| 718 | ((struct tf_version_information_buffer *) ioctl_param); | ||
| 719 | |||
| 720 | dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION1: " | ||
| 721 | "driver_description=\"%64s\"\n", S_VERSION_STRING); | ||
| 722 | |||
| 723 | if (copy_to_user(pInfoBuffer->driver_description, | ||
| 724 | S_VERSION_STRING, | ||
| 725 | strlen(S_VERSION_STRING) + 1)) { | ||
| 726 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
| 727 | "Fail to copy back the driver description " | ||
| 728 | "to %p\n", | ||
| 729 | file, pInfoBuffer->driver_description); | ||
| 730 | result = -EFAULT; | ||
| 731 | goto exit; | ||
| 732 | } | ||
| 733 | |||
| 734 | dprintk(KERN_INFO "IOCTL_TF_GET_DESCRIPTION2: " | ||
| 735 | "secure_world_description=\"%64s\"\n", | ||
| 736 | tf_get_description(&g_tf_dev.sm)); | ||
| 737 | |||
| 738 | if (copy_to_user(pInfoBuffer->secure_world_description, | ||
| 739 | tf_get_description(&g_tf_dev.sm), | ||
| 740 | TF_DESCRIPTION_BUFFER_LENGTH)) { | ||
| 741 | dprintk(KERN_WARNING "tf_device_ioctl(%p): " | ||
| 742 | "Failed to copy back the secure world " | ||
| 743 | "description to %p\n", | ||
| 744 | file, pInfoBuffer->secure_world_description); | ||
| 745 | result = -EFAULT; | ||
| 746 | goto exit; | ||
| 747 | } | ||
| 748 | break; | ||
| 749 | } | ||
| 750 | |||
| 751 | default: | ||
| 752 | dprintk(KERN_ERR "tf_device_ioctl(%p): " | ||
| 753 | "Unknown IOCTL code 0x%08x!\n", | ||
| 754 | file, ioctl_num); | ||
| 755 | result = -EOPNOTSUPP; | ||
| 756 | goto exit; | ||
| 757 | } | ||
| 758 | |||
| 759 | exit: | ||
| 760 | return result; | ||
| 761 | } | ||
| 762 | |||
| 763 | /*----------------------------------------------------------------------------*/ | ||
| 764 | |||
| 765 | static int tf_device_shutdown(void) | ||
| 766 | { | ||
| 767 | |||
| 768 | return tf_power_management(&g_tf_dev.sm, | ||
| 769 | TF_POWER_OPERATION_SHUTDOWN); | ||
| 770 | } | ||
| 771 | |||
| 772 | /*----------------------------------------------------------------------------*/ | ||
| 773 | |||
| 774 | static int tf_device_suspend(void) | ||
| 775 | { | ||
| 776 | dprintk(KERN_INFO "tf_device_suspend: Enter\n"); | ||
| 777 | return tf_power_management(&g_tf_dev.sm, | ||
| 778 | TF_POWER_OPERATION_HIBERNATE); | ||
| 779 | } | ||
| 780 | |||
| 781 | |||
| 782 | /*----------------------------------------------------------------------------*/ | ||
| 783 | |||
| 784 | static int tf_device_resume(void) | ||
| 785 | { | ||
| 786 | return tf_power_management(&g_tf_dev.sm, | ||
| 787 | TF_POWER_OPERATION_RESUME); | ||
| 788 | } | ||
| 789 | |||
| 790 | |||
| 791 | /*----------------------------------------------------------------------------*/ | ||
| 792 | |||
| 793 | module_init(tf_device_register); | ||
| 794 | |||
| 795 | MODULE_LICENSE("GPL"); | ||
| 796 | MODULE_AUTHOR("Trusted Logic S.A."); | ||
diff --git a/security/tf_driver/tf_protocol.h b/security/tf_driver/tf_protocol.h new file mode 100644 index 00000000000..403df8ec8ef --- /dev/null +++ b/security/tf_driver/tf_protocol.h | |||
| @@ -0,0 +1,690 @@ | |||
| 1 | /** | ||
| 2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 17 | * MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef __TF_PROTOCOL_H__ | ||
| 21 | #define __TF_PROTOCOL_H__ | ||
| 22 | |||
| 23 | /*---------------------------------------------------------------------------- | ||
| 24 | * | ||
| 25 | * This header file defines the structure used in the SChannel Protocol. | ||
| 26 | * See your Product Reference Manual for a specification of the SChannel | ||
| 27 | * protocol. | ||
| 28 | *---------------------------------------------------------------------------*/ | ||
| 29 | |||
| 30 | /* | ||
| 31 | * The driver interface version returned by the version ioctl | ||
| 32 | */ | ||
| 33 | #define TF_DRIVER_INTERFACE_VERSION 0x04000000 | ||
| 34 | |||
| 35 | /* | ||
| 36 | * Protocol version handling | ||
| 37 | */ | ||
| 38 | #define TF_S_PROTOCOL_MAJOR_VERSION (0x06) | ||
| 39 | #define GET_PROTOCOL_MAJOR_VERSION(a) (a >> 24) | ||
| 40 | #define GET_PROTOCOL_MINOR_VERSION(a) ((a >> 16) & 0xFF) | ||
| 41 | |||
| 42 | /* | ||
| 43 | * The S flag of the config_flag_s register. | ||
| 44 | */ | ||
| 45 | #define TF_CONFIG_FLAG_S (1 << 3) | ||
| 46 | |||
| 47 | /* | ||
| 48 | * The TimeSlot field of the sync_serial_n register. | ||
| 49 | */ | ||
| 50 | #define TF_SYNC_SERIAL_TIMESLOT_N (1) | ||
| 51 | |||
| 52 | /* | ||
| 53 | * status_s related defines. | ||
| 54 | */ | ||
| 55 | #define TF_STATUS_P_MASK (0X00000001) | ||
| 56 | #define TF_STATUS_POWER_STATE_SHIFT (3) | ||
| 57 | #define TF_STATUS_POWER_STATE_MASK (0x1F << TF_STATUS_POWER_STATE_SHIFT) | ||
| 58 | |||
| 59 | /* | ||
| 60 | * Possible power states of the POWER_STATE field of the status_s register | ||
| 61 | */ | ||
| 62 | #define TF_POWER_MODE_COLD_BOOT (0) | ||
| 63 | #define TF_POWER_MODE_WARM_BOOT (1) | ||
| 64 | #define TF_POWER_MODE_ACTIVE (3) | ||
| 65 | #define TF_POWER_MODE_READY_TO_SHUTDOWN (5) | ||
| 66 | #define TF_POWER_MODE_READY_TO_HIBERNATE (7) | ||
| 67 | #define TF_POWER_MODE_WAKEUP (8) | ||
| 68 | #define TF_POWER_MODE_PANIC (15) | ||
| 69 | |||
| 70 | /* | ||
| 71 | * Possible command values for MANAGEMENT commands | ||
| 72 | */ | ||
| 73 | #define TF_MANAGEMENT_HIBERNATE (1) | ||
| 74 | #define TF_MANAGEMENT_SHUTDOWN (2) | ||
| 75 | #define TF_MANAGEMENT_PREPARE_FOR_CORE_OFF (3) | ||
| 76 | #define TF_MANAGEMENT_RESUME_FROM_CORE_OFF (4) | ||
| 77 | |||
| 78 | /* | ||
| 79 | * The capacity of the Normal Word message queue, in number of slots. | ||
| 80 | */ | ||
| 81 | #define TF_N_MESSAGE_QUEUE_CAPACITY (512) | ||
| 82 | |||
| 83 | /* | ||
| 84 | * The capacity of the Secure World message answer queue, in number of slots. | ||
| 85 | */ | ||
| 86 | #define TF_S_ANSWER_QUEUE_CAPACITY (256) | ||
| 87 | |||
| 88 | /* | ||
| 89 | * The value of the S-timeout register indicating an infinite timeout. | ||
| 90 | */ | ||
| 91 | #define TF_S_TIMEOUT_0_INFINITE (0xFFFFFFFF) | ||
| 92 | #define TF_S_TIMEOUT_1_INFINITE (0xFFFFFFFF) | ||
| 93 | |||
| 94 | /* | ||
| 95 | * The value of the S-timeout register indicating an immediate timeout. | ||
| 96 | */ | ||
| 97 | #define TF_S_TIMEOUT_0_IMMEDIATE (0x0) | ||
| 98 | #define TF_S_TIMEOUT_1_IMMEDIATE (0x0) | ||
| 99 | |||
| 100 | /* | ||
| 101 | * Identifies the get protocol version SMC. | ||
| 102 | */ | ||
| 103 | #define TF_SMC_GET_PROTOCOL_VERSION (0XFFFFFFFB) | ||
| 104 | |||
| 105 | /* | ||
| 106 | * Identifies the init SMC. | ||
| 107 | */ | ||
| 108 | #define TF_SMC_INIT (0XFFFFFFFF) | ||
| 109 | |||
| 110 | /* | ||
| 111 | * Identifies the reset irq SMC. | ||
| 112 | */ | ||
| 113 | #define TF_SMC_RESET_IRQ (0xFFFFFFFE) | ||
| 114 | |||
| 115 | /* | ||
| 116 | * Identifies the SET_W3B SMC. | ||
| 117 | */ | ||
| 118 | #define TF_SMC_WAKE_UP (0xFFFFFFFD) | ||
| 119 | |||
| 120 | /* | ||
| 121 | * Identifies the STOP SMC. | ||
| 122 | */ | ||
| 123 | #define TF_SMC_STOP (0xFFFFFFFC) | ||
| 124 | |||
| 125 | /* | ||
| 126 | * Identifies the n-yield SMC. | ||
| 127 | */ | ||
| 128 | #define TF_SMC_N_YIELD (0X00000003) | ||
| 129 | |||
| 130 | |||
| 131 | /* Possible stop commands for SMC_STOP */ | ||
| 132 | #define SCSTOP_HIBERNATE (0xFFFFFFE1) | ||
| 133 | #define SCSTOP_SHUTDOWN (0xFFFFFFE2) | ||
| 134 | |||
| 135 | /* | ||
| 136 | * representation of an UUID. | ||
| 137 | */ | ||
| 138 | struct tf_uuid { | ||
| 139 | u32 time_low; | ||
| 140 | u16 time_mid; | ||
| 141 | u16 time_hi_and_version; | ||
| 142 | u8 clock_seq_and_node[8]; | ||
| 143 | }; | ||
| 144 | |||
| 145 | |||
| 146 | /** | ||
| 147 | * Command parameters. | ||
| 148 | */ | ||
| 149 | struct tf_command_param_value { | ||
| 150 | u32 a; | ||
| 151 | u32 b; | ||
| 152 | }; | ||
| 153 | |||
| 154 | struct tf_command_param_temp_memref { | ||
| 155 | u32 descriptor; /* data pointer for exchange message.*/ | ||
| 156 | u32 size; | ||
| 157 | u32 offset; | ||
| 158 | }; | ||
| 159 | |||
| 160 | struct tf_command_param_memref { | ||
| 161 | u32 block; | ||
| 162 | u32 size; | ||
| 163 | u32 offset; | ||
| 164 | }; | ||
| 165 | |||
| 166 | union tf_command_param { | ||
| 167 | struct tf_command_param_value value; | ||
| 168 | struct tf_command_param_temp_memref temp_memref; | ||
| 169 | struct tf_command_param_memref memref; | ||
| 170 | }; | ||
| 171 | |||
| 172 | /** | ||
| 173 | * Answer parameters. | ||
| 174 | */ | ||
| 175 | struct tf_answer_param_value { | ||
| 176 | u32 a; | ||
| 177 | u32 b; | ||
| 178 | }; | ||
| 179 | |||
| 180 | struct tf_answer_param_size { | ||
| 181 | u32 _ignored; | ||
| 182 | u32 size; | ||
| 183 | }; | ||
| 184 | |||
| 185 | union tf_answer_param { | ||
| 186 | struct tf_answer_param_size size; | ||
| 187 | struct tf_answer_param_value value; | ||
| 188 | }; | ||
| 189 | |||
| 190 | /* | ||
| 191 | * Descriptor tables capacity | ||
| 192 | */ | ||
| 193 | #define TF_MAX_W3B_COARSE_PAGES (2) | ||
| 194 | /* TF_MAX_COARSE_PAGES is the number of level 1 descriptors (describing | ||
| 195 | * 1MB each) that can be shared with the secure world in a single registered | ||
| 196 | * shared memory block. It must be kept in synch with | ||
| 197 | * SCHANNEL6_MAX_DESCRIPTORS_PER_REGISTERED_SHARED_MEM in the SChannel | ||
| 198 | * protocol spec. */ | ||
| 199 | #define TF_MAX_COARSE_PAGES 128 | ||
| 200 | #define TF_DESCRIPTOR_TABLE_CAPACITY_BIT_SHIFT (8) | ||
| 201 | #define TF_DESCRIPTOR_TABLE_CAPACITY \ | ||
| 202 | (1 << TF_DESCRIPTOR_TABLE_CAPACITY_BIT_SHIFT) | ||
| 203 | #define TF_DESCRIPTOR_TABLE_CAPACITY_MASK \ | ||
| 204 | (TF_DESCRIPTOR_TABLE_CAPACITY - 1) | ||
| 205 | /* Shared memories coarse pages can map up to 1MB */ | ||
| 206 | #define TF_MAX_COARSE_PAGE_MAPPED_SIZE \ | ||
| 207 | (PAGE_SIZE * TF_DESCRIPTOR_TABLE_CAPACITY) | ||
| 208 | /* Shared memories cannot exceed 8MB */ | ||
| 209 | #define TF_MAX_SHMEM_SIZE \ | ||
| 210 | (TF_MAX_COARSE_PAGE_MAPPED_SIZE << 3) | ||
| 211 | |||
| 212 | /* | ||
| 213 | * Buffer size for version description fields | ||
| 214 | */ | ||
| 215 | #define TF_DESCRIPTION_BUFFER_LENGTH 64 | ||
| 216 | |||
| 217 | /* | ||
| 218 | * Shared memory type flags. | ||
| 219 | */ | ||
| 220 | #define TF_SHMEM_TYPE_READ (0x00000001) | ||
| 221 | #define TF_SHMEM_TYPE_WRITE (0x00000002) | ||
| 222 | |||
| 223 | /* | ||
| 224 | * Shared mem flags | ||
| 225 | */ | ||
| 226 | #define TF_SHARED_MEM_FLAG_INPUT 1 | ||
| 227 | #define TF_SHARED_MEM_FLAG_OUTPUT 2 | ||
| 228 | #define TF_SHARED_MEM_FLAG_INOUT 3 | ||
| 229 | |||
| 230 | |||
| 231 | /* | ||
| 232 | * Parameter types | ||
| 233 | */ | ||
| 234 | #define TF_PARAM_TYPE_NONE 0x0 | ||
| 235 | #define TF_PARAM_TYPE_VALUE_INPUT 0x1 | ||
| 236 | #define TF_PARAM_TYPE_VALUE_OUTPUT 0x2 | ||
| 237 | #define TF_PARAM_TYPE_VALUE_INOUT 0x3 | ||
| 238 | #define TF_PARAM_TYPE_MEMREF_TEMP_INPUT 0x5 | ||
| 239 | #define TF_PARAM_TYPE_MEMREF_TEMP_OUTPUT 0x6 | ||
| 240 | #define TF_PARAM_TYPE_MEMREF_TEMP_INOUT 0x7 | ||
| 241 | #define TF_PARAM_TYPE_MEMREF_INPUT 0xD | ||
| 242 | #define TF_PARAM_TYPE_MEMREF_OUTPUT 0xE | ||
| 243 | #define TF_PARAM_TYPE_MEMREF_INOUT 0xF | ||
| 244 | |||
| 245 | #define TF_PARAM_TYPE_MEMREF_FLAG 0x4 | ||
| 246 | #define TF_PARAM_TYPE_REGISTERED_MEMREF_FLAG 0x8 | ||
| 247 | |||
| 248 | |||
| 249 | #define TF_MAKE_PARAM_TYPES(t0, t1, t2, t3) \ | ||
| 250 | ((t0) | ((t1) << 4) | ((t2) << 8) | ((t3) << 12)) | ||
| 251 | #define TF_GET_PARAM_TYPE(t, i) (((t) >> (4 * i)) & 0xF) | ||
| 252 | |||
| 253 | /* | ||
| 254 | * Login types. | ||
| 255 | */ | ||
| 256 | #define TF_LOGIN_PUBLIC 0x00000000 | ||
| 257 | #define TF_LOGIN_USER 0x00000001 | ||
| 258 | #define TF_LOGIN_GROUP 0x00000002 | ||
| 259 | #define TF_LOGIN_APPLICATION 0x00000004 | ||
| 260 | #define TF_LOGIN_APPLICATION_USER 0x00000005 | ||
| 261 | #define TF_LOGIN_APPLICATION_GROUP 0x00000006 | ||
| 262 | #define TF_LOGIN_AUTHENTICATION 0x80000000 | ||
| 263 | #define TF_LOGIN_PRIVILEGED 0x80000002 | ||
| 264 | |||
| 265 | /* Login variants */ | ||
| 266 | |||
| 267 | #define TF_LOGIN_VARIANT(main_type, os, variant) \ | ||
| 268 | ((main_type) | (1 << 27) | ((os) << 16) | ((variant) << 8)) | ||
| 269 | |||
| 270 | #define TF_LOGIN_GET_MAIN_TYPE(type) \ | ||
| 271 | ((type) & ~TF_LOGIN_VARIANT(0, 0xFF, 0xFF)) | ||
| 272 | |||
| 273 | #define TF_LOGIN_OS_ANY 0x00 | ||
| 274 | #define TF_LOGIN_OS_LINUX 0x01 | ||
| 275 | #define TF_LOGIN_OS_ANDROID 0x04 | ||
| 276 | |||
| 277 | /* OS-independent variants */ | ||
| 278 | #define TF_LOGIN_USER_NONE \ | ||
| 279 | TF_LOGIN_VARIANT(TF_LOGIN_USER, TF_LOGIN_OS_ANY, 0xFF) | ||
| 280 | #define TF_LOGIN_GROUP_NONE \ | ||
| 281 | TF_LOGIN_VARIANT(TF_LOGIN_GROUP, TF_LOGIN_OS_ANY, 0xFF) | ||
| 282 | #define TF_LOGIN_APPLICATION_USER_NONE \ | ||
| 283 | TF_LOGIN_VARIANT(TF_LOGIN_APPLICATION_USER, TF_LOGIN_OS_ANY, 0xFF) | ||
| 284 | #define TF_LOGIN_AUTHENTICATION_BINARY_SHA1_HASH \ | ||
| 285 | TF_LOGIN_VARIANT(TF_LOGIN_AUTHENTICATION, TF_LOGIN_OS_ANY, 0x01) | ||
| 286 | #define TF_LOGIN_PRIVILEGED_KERNEL \ | ||
| 287 | TF_LOGIN_VARIANT(TF_LOGIN_PRIVILEGED, TF_LOGIN_OS_ANY, 0x01) | ||
| 288 | |||
| 289 | /* Linux variants */ | ||
| 290 | #define TF_LOGIN_USER_LINUX_EUID \ | ||
| 291 | TF_LOGIN_VARIANT(TF_LOGIN_USER, TF_LOGIN_OS_LINUX, 0x01) | ||
| 292 | #define TF_LOGIN_GROUP_LINUX_GID \ | ||
| 293 | TF_LOGIN_VARIANT(TF_LOGIN_GROUP, TF_LOGIN_OS_LINUX, 0x01) | ||
| 294 | #define TF_LOGIN_APPLICATION_LINUX_PATH_SHA1_HASH \ | ||
| 295 | TF_LOGIN_VARIANT(TF_LOGIN_APPLICATION, TF_LOGIN_OS_LINUX, 0x01) | ||
| 296 | #define TF_LOGIN_APPLICATION_USER_LINUX_PATH_EUID_SHA1_HASH \ | ||
| 297 | TF_LOGIN_VARIANT(TF_LOGIN_APPLICATION_USER, TF_LOGIN_OS_LINUX, 0x01) | ||
| 298 | #define TF_LOGIN_APPLICATION_GROUP_LINUX_PATH_GID_SHA1_HASH \ | ||
| 299 | TF_LOGIN_VARIANT(TF_LOGIN_APPLICATION_GROUP, TF_LOGIN_OS_LINUX, 0x01) | ||
| 300 | |||
| 301 | /* Android variants */ | ||
| 302 | #define TF_LOGIN_USER_ANDROID_EUID \ | ||
| 303 | TF_LOGIN_VARIANT(TF_LOGIN_USER, TF_LOGIN_OS_ANDROID, 0x01) | ||
| 304 | #define TF_LOGIN_GROUP_ANDROID_GID \ | ||
| 305 | TF_LOGIN_VARIANT(TF_LOGIN_GROUP, TF_LOGIN_OS_ANDROID, 0x01) | ||
| 306 | #define TF_LOGIN_APPLICATION_ANDROID_UID \ | ||
| 307 | TF_LOGIN_VARIANT(TF_LOGIN_APPLICATION, TF_LOGIN_OS_ANDROID, 0x01) | ||
| 308 | #define TF_LOGIN_APPLICATION_USER_ANDROID_UID_EUID \ | ||
| 309 | TF_LOGIN_VARIANT(TF_LOGIN_APPLICATION_USER, TF_LOGIN_OS_ANDROID, \ | ||
| 310 | 0x01) | ||
| 311 | #define TF_LOGIN_APPLICATION_GROUP_ANDROID_UID_GID \ | ||
| 312 | TF_LOGIN_VARIANT(TF_LOGIN_APPLICATION_GROUP, TF_LOGIN_OS_ANDROID, \ | ||
| 313 | 0x01) | ||
| 314 | |||
| 315 | /* | ||
| 316 | * return origins | ||
| 317 | */ | ||
| 318 | #define TF_ORIGIN_COMMS 2 | ||
| 319 | #define TF_ORIGIN_TEE 3 | ||
| 320 | #define TF_ORIGIN_TRUSTED_APP 4 | ||
| 321 | /* | ||
| 322 | * The message types. | ||
| 323 | */ | ||
| 324 | #define TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT 0x02 | ||
| 325 | #define TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT 0xFD | ||
| 326 | #define TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY 0xF7 | ||
| 327 | #define TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY 0xF9 | ||
| 328 | #define TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION 0xF0 | ||
| 329 | #define TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION 0xF2 | ||
| 330 | #define TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND 0xF5 | ||
| 331 | #define TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND 0xF4 | ||
| 332 | #define TF_MESSAGE_TYPE_MANAGEMENT 0xFE | ||
| 333 | |||
| 334 | |||
| 335 | /* | ||
| 336 | * The SChannel error codes. | ||
| 337 | */ | ||
| 338 | #define S_SUCCESS 0x00000000 | ||
| 339 | #define S_ERROR_OUT_OF_MEMORY 0xFFFF000C | ||
| 340 | |||
| 341 | |||
| 342 | struct tf_command_header { | ||
| 343 | u8 message_size; | ||
| 344 | u8 message_type; | ||
| 345 | u16 message_info; | ||
| 346 | u32 operation_id; | ||
| 347 | }; | ||
| 348 | |||
| 349 | struct tf_answer_header { | ||
| 350 | u8 message_size; | ||
| 351 | u8 message_type; | ||
| 352 | u16 message_info; | ||
| 353 | u32 operation_id; | ||
| 354 | u32 error_code; | ||
| 355 | }; | ||
| 356 | |||
| 357 | /* | ||
| 358 | * CREATE_DEVICE_CONTEXT command message. | ||
| 359 | */ | ||
| 360 | struct tf_command_create_device_context { | ||
| 361 | u8 message_size; | ||
| 362 | u8 message_type; | ||
| 363 | u16 message_info_rfu; | ||
| 364 | u32 operation_id; | ||
| 365 | u32 device_context_id; | ||
| 366 | }; | ||
| 367 | |||
| 368 | /* | ||
| 369 | * CREATE_DEVICE_CONTEXT answer message. | ||
| 370 | */ | ||
| 371 | struct tf_answer_create_device_context { | ||
| 372 | u8 message_size; | ||
| 373 | u8 message_type; | ||
| 374 | u16 message_info_rfu; | ||
| 375 | /* an opaque Normal World identifier for the operation */ | ||
| 376 | u32 operation_id; | ||
| 377 | u32 error_code; | ||
| 378 | /* an opaque Normal World identifier for the device context */ | ||
| 379 | u32 device_context; | ||
| 380 | }; | ||
| 381 | |||
| 382 | /* | ||
| 383 | * DESTROY_DEVICE_CONTEXT command message. | ||
| 384 | */ | ||
| 385 | struct tf_command_destroy_device_context { | ||
| 386 | u8 message_size; | ||
| 387 | u8 message_type; | ||
| 388 | u16 message_info_rfu; | ||
| 389 | u32 operation_id; | ||
| 390 | u32 device_context; | ||
| 391 | }; | ||
| 392 | |||
| 393 | /* | ||
| 394 | * DESTROY_DEVICE_CONTEXT answer message. | ||
| 395 | */ | ||
| 396 | struct tf_answer_destroy_device_context { | ||
| 397 | u8 message_size; | ||
| 398 | u8 message_type; | ||
| 399 | u16 message_info_rfu; | ||
| 400 | /* an opaque Normal World identifier for the operation */ | ||
| 401 | u32 operation_id; | ||
| 402 | u32 error_code; | ||
| 403 | u32 device_context_id; | ||
| 404 | }; | ||
| 405 | |||
| 406 | /* | ||
| 407 | * OPEN_CLIENT_SESSION command message. | ||
| 408 | */ | ||
| 409 | struct tf_command_open_client_session { | ||
| 410 | u8 message_size; | ||
| 411 | u8 message_type; | ||
| 412 | u16 param_types; | ||
| 413 | /* an opaque Normal World identifier for the operation */ | ||
| 414 | u32 operation_id; | ||
| 415 | u32 device_context; | ||
| 416 | u32 cancellation_id; | ||
| 417 | u64 timeout; | ||
| 418 | struct tf_uuid destination_uuid; | ||
| 419 | union tf_command_param params[4]; | ||
| 420 | u32 login_type; | ||
| 421 | /* | ||
| 422 | * Size = 0 for public, [16] for group identification, [20] for | ||
| 423 | * authentication | ||
| 424 | */ | ||
| 425 | u8 login_data[20]; | ||
| 426 | }; | ||
| 427 | |||
| 428 | /* | ||
| 429 | * OPEN_CLIENT_SESSION answer message. | ||
| 430 | */ | ||
| 431 | struct tf_answer_open_client_session { | ||
| 432 | u8 message_size; | ||
| 433 | u8 message_type; | ||
| 434 | u8 error_origin; | ||
| 435 | u8 __reserved; | ||
| 436 | /* an opaque Normal World identifier for the operation */ | ||
| 437 | u32 operation_id; | ||
| 438 | u32 error_code; | ||
| 439 | u32 client_session; | ||
| 440 | union tf_answer_param answers[4]; | ||
| 441 | }; | ||
| 442 | |||
| 443 | /* | ||
| 444 | * CLOSE_CLIENT_SESSION command message. | ||
| 445 | */ | ||
| 446 | struct tf_command_close_client_session { | ||
| 447 | u8 message_size; | ||
| 448 | u8 message_type; | ||
| 449 | u16 message_info_rfu; | ||
| 450 | /* an opaque Normal World identifier for the operation */ | ||
| 451 | u32 operation_id; | ||
| 452 | u32 device_context; | ||
| 453 | u32 client_session; | ||
| 454 | }; | ||
| 455 | |||
| 456 | /* | ||
| 457 | * CLOSE_CLIENT_SESSION answer message. | ||
| 458 | */ | ||
| 459 | struct tf_answer_close_client_session { | ||
| 460 | u8 message_size; | ||
| 461 | u8 message_type; | ||
| 462 | u16 message_info_rfu; | ||
| 463 | /* an opaque Normal World identifier for the operation */ | ||
| 464 | u32 operation_id; | ||
| 465 | u32 error_code; | ||
| 466 | }; | ||
| 467 | |||
| 468 | |||
| 469 | /* | ||
| 470 | * REGISTER_SHARED_MEMORY command message | ||
| 471 | */ | ||
| 472 | struct tf_command_register_shared_memory { | ||
| 473 | u8 message_size; | ||
| 474 | u8 message_type; | ||
| 475 | u16 memory_flags; | ||
| 476 | u32 operation_id; | ||
| 477 | u32 device_context; | ||
| 478 | u32 block_id; | ||
| 479 | u32 shared_mem_size; | ||
| 480 | u32 shared_mem_start_offset; | ||
| 481 | u32 shared_mem_descriptors[TF_MAX_COARSE_PAGES]; | ||
| 482 | }; | ||
| 483 | |||
| 484 | /* | ||
| 485 | * REGISTER_SHARED_MEMORY answer message. | ||
| 486 | */ | ||
| 487 | struct tf_answer_register_shared_memory { | ||
| 488 | u8 message_size; | ||
| 489 | u8 message_type; | ||
| 490 | u16 message_info_rfu; | ||
| 491 | /* an opaque Normal World identifier for the operation */ | ||
| 492 | u32 operation_id; | ||
| 493 | u32 error_code; | ||
| 494 | u32 block; | ||
| 495 | }; | ||
| 496 | |||
| 497 | /* | ||
| 498 | * RELEASE_SHARED_MEMORY command message. | ||
| 499 | */ | ||
| 500 | struct tf_command_release_shared_memory { | ||
| 501 | u8 message_size; | ||
| 502 | u8 message_type; | ||
| 503 | u16 message_info_rfu; | ||
| 504 | /* an opaque Normal World identifier for the operation */ | ||
| 505 | u32 operation_id; | ||
| 506 | u32 device_context; | ||
| 507 | u32 block; | ||
| 508 | }; | ||
| 509 | |||
| 510 | /* | ||
| 511 | * RELEASE_SHARED_MEMORY answer message. | ||
| 512 | */ | ||
| 513 | struct tf_answer_release_shared_memory { | ||
| 514 | u8 message_size; | ||
| 515 | u8 message_type; | ||
| 516 | u16 message_info_rfu; | ||
| 517 | u32 operation_id; | ||
| 518 | u32 error_code; | ||
| 519 | u32 block_id; | ||
| 520 | }; | ||
| 521 | |||
| 522 | /* | ||
| 523 | * INVOKE_CLIENT_COMMAND command message. | ||
| 524 | */ | ||
| 525 | struct tf_command_invoke_client_command { | ||
| 526 | u8 message_size; | ||
| 527 | u8 message_type; | ||
| 528 | u16 param_types; | ||
| 529 | u32 operation_id; | ||
| 530 | u32 device_context; | ||
| 531 | u32 client_session; | ||
| 532 | u64 timeout; | ||
| 533 | u32 cancellation_id; | ||
| 534 | u32 client_command_identifier; | ||
| 535 | union tf_command_param params[4]; | ||
| 536 | }; | ||
| 537 | |||
| 538 | /* | ||
| 539 | * INVOKE_CLIENT_COMMAND command answer. | ||
| 540 | */ | ||
| 541 | struct tf_answer_invoke_client_command { | ||
| 542 | u8 message_size; | ||
| 543 | u8 message_type; | ||
| 544 | u8 error_origin; | ||
| 545 | u8 __reserved; | ||
| 546 | u32 operation_id; | ||
| 547 | u32 error_code; | ||
| 548 | union tf_answer_param answers[4]; | ||
| 549 | }; | ||
| 550 | |||
| 551 | /* | ||
| 552 | * CANCEL_CLIENT_OPERATION command message. | ||
| 553 | */ | ||
| 554 | struct tf_command_cancel_client_operation { | ||
| 555 | u8 message_size; | ||
| 556 | u8 message_type; | ||
| 557 | u16 message_info_rfu; | ||
| 558 | /* an opaque Normal World identifier for the operation */ | ||
| 559 | u32 operation_id; | ||
| 560 | u32 device_context; | ||
| 561 | u32 client_session; | ||
| 562 | u32 cancellation_id; | ||
| 563 | }; | ||
| 564 | |||
| 565 | struct tf_answer_cancel_client_operation { | ||
| 566 | u8 message_size; | ||
| 567 | u8 message_type; | ||
| 568 | u16 message_info_rfu; | ||
| 569 | u32 operation_id; | ||
| 570 | u32 error_code; | ||
| 571 | }; | ||
| 572 | |||
| 573 | /* | ||
| 574 | * MANAGEMENT command message. | ||
| 575 | */ | ||
| 576 | struct tf_command_management { | ||
| 577 | u8 message_size; | ||
| 578 | u8 message_type; | ||
| 579 | u16 command; | ||
| 580 | u32 operation_id; | ||
| 581 | u32 w3b_size; | ||
| 582 | u32 w3b_start_offset; | ||
| 583 | u32 shared_mem_descriptors[1]; | ||
| 584 | }; | ||
| 585 | |||
| 586 | /* | ||
| 587 | * POWER_MANAGEMENT answer message. | ||
| 588 | * The message does not provide message specific parameters. | ||
| 589 | * Therefore no need to define a specific answer structure | ||
| 590 | */ | ||
| 591 | |||
| 592 | /* | ||
| 593 | * Structure for L2 messages | ||
| 594 | */ | ||
| 595 | union tf_command { | ||
| 596 | struct tf_command_header header; | ||
| 597 | struct tf_command_create_device_context create_device_context; | ||
| 598 | struct tf_command_destroy_device_context destroy_device_context; | ||
| 599 | struct tf_command_open_client_session open_client_session; | ||
| 600 | struct tf_command_close_client_session close_client_session; | ||
| 601 | struct tf_command_register_shared_memory register_shared_memory; | ||
| 602 | struct tf_command_release_shared_memory release_shared_memory; | ||
| 603 | struct tf_command_invoke_client_command invoke_client_command; | ||
| 604 | struct tf_command_cancel_client_operation cancel_client_operation; | ||
| 605 | struct tf_command_management management; | ||
| 606 | }; | ||
| 607 | |||
| 608 | /* | ||
| 609 | * Structure for any L2 answer | ||
| 610 | */ | ||
| 611 | |||
| 612 | union tf_answer { | ||
| 613 | struct tf_answer_header header; | ||
| 614 | struct tf_answer_create_device_context create_device_context; | ||
| 615 | struct tf_answer_open_client_session open_client_session; | ||
| 616 | struct tf_answer_close_client_session close_client_session; | ||
| 617 | struct tf_answer_register_shared_memory register_shared_memory; | ||
| 618 | struct tf_answer_release_shared_memory release_shared_memory; | ||
| 619 | struct tf_answer_invoke_client_command invoke_client_command; | ||
| 620 | struct tf_answer_destroy_device_context destroy_device_context; | ||
| 621 | struct tf_answer_cancel_client_operation cancel_client_operation; | ||
| 622 | }; | ||
| 623 | |||
| 624 | /* Structure of the Communication Buffer */ | ||
| 625 | struct tf_l1_shared_buffer { | ||
| 626 | #ifdef CONFIG_TF_ZEBRA | ||
| 627 | u32 exit_code; | ||
| 628 | u32 l1_shared_buffer_descr; | ||
| 629 | u32 backing_store_addr; | ||
| 630 | u32 backext_storage_addr; | ||
| 631 | u32 workspace_addr; | ||
| 632 | u32 workspace_size; | ||
| 633 | u32 conf_descriptor; | ||
| 634 | u32 conf_size; | ||
| 635 | u32 conf_offset; | ||
| 636 | u32 protocol_version; | ||
| 637 | u32 rpc_command; | ||
| 638 | u32 rpc_status; | ||
| 639 | u8 reserved1[16]; | ||
| 640 | #else | ||
| 641 | u32 config_flag_s; | ||
| 642 | u32 w3b_size_max_s; | ||
| 643 | u32 reserved0; | ||
| 644 | u32 w3b_size_current_s; | ||
| 645 | u8 reserved1[48]; | ||
| 646 | #endif | ||
| 647 | u8 version_description[TF_DESCRIPTION_BUFFER_LENGTH]; | ||
| 648 | u32 status_s; | ||
| 649 | u32 reserved2; | ||
| 650 | u32 sync_serial_n; | ||
| 651 | u32 sync_serial_s; | ||
| 652 | u64 time_n[2]; | ||
| 653 | u64 timeout_s[2]; | ||
| 654 | u32 first_command; | ||
| 655 | u32 first_free_command; | ||
| 656 | u32 first_answer; | ||
| 657 | u32 first_free_answer; | ||
| 658 | u32 w3b_descriptors[128]; | ||
| 659 | #ifdef CONFIG_TF_ZEBRA | ||
| 660 | u8 rpc_trace_buffer[140]; | ||
| 661 | u8 rpc_cus_buffer[180]; | ||
| 662 | #else | ||
| 663 | u8 reserved3[320]; | ||
| 664 | #endif | ||
| 665 | u32 command_queue[TF_N_MESSAGE_QUEUE_CAPACITY]; | ||
| 666 | u32 answer_queue[TF_S_ANSWER_QUEUE_CAPACITY]; | ||
| 667 | }; | ||
| 668 | |||
| 669 | |||
| 670 | /* | ||
| 671 | * tf_version_information_buffer structure description | ||
| 672 | * Description of the sVersionBuffer handed over from user space to kernel space | ||
| 673 | * This field is filled by the driver during a CREATE_DEVICE_CONTEXT ioctl | ||
| 674 | * and handed back to user space | ||
| 675 | */ | ||
| 676 | struct tf_version_information_buffer { | ||
| 677 | u8 driver_description[65]; | ||
| 678 | u8 secure_world_description[65]; | ||
| 679 | }; | ||
| 680 | |||
| 681 | |||
| 682 | /* The IOCTLs the driver supports */ | ||
| 683 | #include <linux/ioctl.h> | ||
| 684 | |||
| 685 | #define IOCTL_TF_GET_VERSION _IO('z', 0) | ||
| 686 | #define IOCTL_TF_EXCHANGE _IOWR('z', 1, union tf_command) | ||
| 687 | #define IOCTL_TF_GET_DESCRIPTION _IOR('z', 2, \ | ||
| 688 | struct tf_version_information_buffer) | ||
| 689 | |||
| 690 | #endif /* !defined(__TF_PROTOCOL_H__) */ | ||
diff --git a/security/tf_driver/tf_util.c b/security/tf_driver/tf_util.c new file mode 100644 index 00000000000..78f90bf677e --- /dev/null +++ b/security/tf_driver/tf_util.c | |||
| @@ -0,0 +1,1143 @@ | |||
| 1 | /** | ||
| 2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 17 | * MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/mman.h> | ||
| 21 | #include "tf_util.h" | ||
| 22 | |||
| 23 | /*---------------------------------------------------------------------------- | ||
| 24 | * Debug printing routines | ||
| 25 | *----------------------------------------------------------------------------*/ | ||
| 26 | #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT | ||
| 27 | |||
| 28 | void tf_trace_array(const char *fun, const char *msg, | ||
| 29 | const void *ptr, size_t len) | ||
| 30 | { | ||
| 31 | char hex[511]; | ||
| 32 | bool ell = (len > sizeof(hex)/2); | ||
| 33 | unsigned lim = (len > sizeof(hex)/2 ? sizeof(hex)/2 : len); | ||
| 34 | unsigned i; | ||
| 35 | for (i = 0; i < lim; i++) | ||
| 36 | sprintf(hex + 2 * i, "%02x", ((unsigned char *)ptr)[i]); | ||
| 37 | pr_info("%s: %s[%u] = %s%s\n", | ||
| 38 | fun, msg, len, hex, ell ? "..." : ""); | ||
| 39 | } | ||
| 40 | |||
| 41 | void address_cache_property(unsigned long va) | ||
| 42 | { | ||
| 43 | unsigned long pa; | ||
| 44 | unsigned long inner; | ||
| 45 | unsigned long outer; | ||
| 46 | |||
| 47 | asm volatile ("mcr p15, 0, %0, c7, c8, 0" : : "r" (va)); | ||
| 48 | asm volatile ("mrc p15, 0, %0, c7, c4, 0" : "=r" (pa)); | ||
| 49 | |||
| 50 | dprintk(KERN_INFO "VA:%x, PA:%x\n", | ||
| 51 | (unsigned int) va, | ||
| 52 | (unsigned int) pa); | ||
| 53 | |||
| 54 | if (pa & 1) { | ||
| 55 | dprintk(KERN_INFO "Prop Error\n"); | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | |||
| 59 | outer = (pa >> 2) & 3; | ||
| 60 | dprintk(KERN_INFO "\touter : %x", (unsigned int) outer); | ||
| 61 | |||
| 62 | switch (outer) { | ||
| 63 | case 3: | ||
| 64 | dprintk(KERN_INFO "Write-Back, no Write-Allocate\n"); | ||
| 65 | break; | ||
| 66 | case 2: | ||
| 67 | dprintk(KERN_INFO "Write-Through, no Write-Allocate.\n"); | ||
| 68 | break; | ||
| 69 | case 1: | ||
| 70 | dprintk(KERN_INFO "Write-Back, Write-Allocate.\n"); | ||
| 71 | break; | ||
| 72 | case 0: | ||
| 73 | dprintk(KERN_INFO "Non-cacheable.\n"); | ||
| 74 | break; | ||
| 75 | } | ||
| 76 | |||
| 77 | inner = (pa >> 4) & 7; | ||
| 78 | dprintk(KERN_INFO "\tinner : %x", (unsigned int)inner); | ||
| 79 | |||
| 80 | switch (inner) { | ||
| 81 | case 7: | ||
| 82 | dprintk(KERN_INFO "Write-Back, no Write-Allocate\n"); | ||
| 83 | break; | ||
| 84 | case 6: | ||
| 85 | dprintk(KERN_INFO "Write-Through.\n"); | ||
| 86 | break; | ||
| 87 | case 5: | ||
| 88 | dprintk(KERN_INFO "Write-Back, Write-Allocate.\n"); | ||
| 89 | break; | ||
| 90 | case 3: | ||
| 91 | dprintk(KERN_INFO "Device.\n"); | ||
| 92 | break; | ||
| 93 | case 1: | ||
| 94 | dprintk(KERN_INFO "Strongly-ordered.\n"); | ||
| 95 | break; | ||
| 96 | case 0: | ||
| 97 | dprintk(KERN_INFO "Non-cacheable.\n"); | ||
| 98 | break; | ||
| 99 | } | ||
| 100 | |||
| 101 | if (pa & 0x00000002) | ||
| 102 | dprintk(KERN_INFO "SuperSection.\n"); | ||
| 103 | if (pa & 0x00000080) | ||
| 104 | dprintk(KERN_INFO "Memory is shareable.\n"); | ||
| 105 | else | ||
| 106 | dprintk(KERN_INFO "Memory is non-shareable.\n"); | ||
| 107 | |||
| 108 | if (pa & 0x00000200) | ||
| 109 | dprintk(KERN_INFO "Non-secure.\n"); | ||
| 110 | } | ||
| 111 | |||
| 112 | /* | ||
| 113 | * Dump the L1 shared buffer. | ||
| 114 | */ | ||
| 115 | void tf_dump_l1_shared_buffer(struct tf_l1_shared_buffer *buffer) | ||
| 116 | { | ||
| 117 | dprintk(KERN_INFO | ||
| 118 | "buffer@%p:\n" | ||
| 119 | #ifndef CONFIG_TF_ZEBRA | ||
| 120 | " config_flag_s=%08X\n" | ||
| 121 | #endif | ||
| 122 | " version_description=%64s\n" | ||
| 123 | " status_s=%08X\n" | ||
| 124 | " sync_serial_n=%08X\n" | ||
| 125 | " sync_serial_s=%08X\n" | ||
| 126 | " time_n[0]=%016llX\n" | ||
| 127 | " time_n[1]=%016llX\n" | ||
| 128 | " timeout_s[0]=%016llX\n" | ||
| 129 | " timeout_s[1]=%016llX\n" | ||
| 130 | " first_command=%08X\n" | ||
| 131 | " first_free_command=%08X\n" | ||
| 132 | " first_answer=%08X\n" | ||
| 133 | " first_free_answer=%08X\n\n", | ||
| 134 | buffer, | ||
| 135 | #ifndef CONFIG_TF_ZEBRA | ||
| 136 | buffer->config_flag_s, | ||
| 137 | #endif | ||
| 138 | buffer->version_description, | ||
| 139 | buffer->status_s, | ||
| 140 | buffer->sync_serial_n, | ||
| 141 | buffer->sync_serial_s, | ||
| 142 | buffer->time_n[0], | ||
| 143 | buffer->time_n[1], | ||
| 144 | buffer->timeout_s[0], | ||
| 145 | buffer->timeout_s[1], | ||
| 146 | buffer->first_command, | ||
| 147 | buffer->first_free_command, | ||
| 148 | buffer->first_answer, | ||
| 149 | buffer->first_free_answer); | ||
| 150 | } | ||
| 151 | |||
| 152 | |||
| 153 | /* | ||
| 154 | * Dump the specified SChannel message using dprintk. | ||
| 155 | */ | ||
| 156 | void tf_dump_command(union tf_command *command) | ||
| 157 | { | ||
| 158 | u32 i; | ||
| 159 | |||
| 160 | dprintk(KERN_INFO "message@%p:\n", command); | ||
| 161 | |||
| 162 | switch (command->header.message_type) { | ||
| 163 | case TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT: | ||
| 164 | dprintk(KERN_INFO | ||
| 165 | " message_size = 0x%02X\n" | ||
| 166 | " message_type = 0x%02X " | ||
| 167 | "TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT\n" | ||
| 168 | " operation_id = 0x%08X\n" | ||
| 169 | " device_context_id = 0x%08X\n", | ||
| 170 | command->header.message_size, | ||
| 171 | command->header.message_type, | ||
| 172 | command->header.operation_id, | ||
| 173 | command->create_device_context.device_context_id | ||
| 174 | ); | ||
| 175 | break; | ||
| 176 | |||
| 177 | case TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT: | ||
| 178 | dprintk(KERN_INFO | ||
| 179 | " message_size = 0x%02X\n" | ||
| 180 | " message_type = 0x%02X " | ||
| 181 | "TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT\n" | ||
| 182 | " operation_id = 0x%08X\n" | ||
| 183 | " device_context = 0x%08X\n", | ||
| 184 | command->header.message_size, | ||
| 185 | command->header.message_type, | ||
| 186 | command->header.operation_id, | ||
| 187 | command->destroy_device_context.device_context); | ||
| 188 | break; | ||
| 189 | |||
| 190 | case TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION: | ||
| 191 | dprintk(KERN_INFO | ||
| 192 | " message_size = 0x%02X\n" | ||
| 193 | " message_type = 0x%02X " | ||
| 194 | "TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION\n" | ||
| 195 | " param_types = 0x%04X\n" | ||
| 196 | " operation_id = 0x%08X\n" | ||
| 197 | " device_context = 0x%08X\n" | ||
| 198 | " cancellation_id = 0x%08X\n" | ||
| 199 | " timeout = 0x%016llX\n" | ||
| 200 | " destination_uuid = " | ||
| 201 | "%08X-%04X-%04X-%02X%02X-" | ||
| 202 | "%02X%02X%02X%02X%02X%02X\n", | ||
| 203 | command->header.message_size, | ||
| 204 | command->header.message_type, | ||
| 205 | command->open_client_session.param_types, | ||
| 206 | command->header.operation_id, | ||
| 207 | command->open_client_session.device_context, | ||
| 208 | command->open_client_session.cancellation_id, | ||
| 209 | command->open_client_session.timeout, | ||
| 210 | command->open_client_session.destination_uuid. | ||
| 211 | time_low, | ||
| 212 | command->open_client_session.destination_uuid. | ||
| 213 | time_mid, | ||
| 214 | command->open_client_session.destination_uuid. | ||
| 215 | time_hi_and_version, | ||
| 216 | command->open_client_session.destination_uuid. | ||
| 217 | clock_seq_and_node[0], | ||
| 218 | command->open_client_session.destination_uuid. | ||
| 219 | clock_seq_and_node[1], | ||
| 220 | command->open_client_session.destination_uuid. | ||
| 221 | clock_seq_and_node[2], | ||
| 222 | command->open_client_session.destination_uuid. | ||
| 223 | clock_seq_and_node[3], | ||
| 224 | command->open_client_session.destination_uuid. | ||
| 225 | clock_seq_and_node[4], | ||
| 226 | command->open_client_session.destination_uuid. | ||
| 227 | clock_seq_and_node[5], | ||
| 228 | command->open_client_session.destination_uuid. | ||
| 229 | clock_seq_and_node[6], | ||
| 230 | command->open_client_session.destination_uuid. | ||
| 231 | clock_seq_and_node[7] | ||
| 232 | ); | ||
| 233 | |||
| 234 | for (i = 0; i < 4; i++) { | ||
| 235 | uint32_t *param = (uint32_t *) &command-> | ||
| 236 | open_client_session.params[i]; | ||
| 237 | dprintk(KERN_INFO " params[%d] = " | ||
| 238 | "0x%08X:0x%08X:0x%08X\n", | ||
| 239 | i, param[0], param[1], param[2]); | ||
| 240 | } | ||
| 241 | |||
| 242 | switch (TF_LOGIN_GET_MAIN_TYPE( | ||
| 243 | command->open_client_session.login_type)) { | ||
| 244 | case TF_LOGIN_PUBLIC: | ||
| 245 | dprintk( | ||
| 246 | KERN_INFO " login_type = " | ||
| 247 | "TF_LOGIN_PUBLIC\n"); | ||
| 248 | break; | ||
| 249 | case TF_LOGIN_USER: | ||
| 250 | dprintk( | ||
| 251 | KERN_INFO " login_type = " | ||
| 252 | "TF_LOGIN_USER\n"); | ||
| 253 | break; | ||
| 254 | case TF_LOGIN_GROUP: | ||
| 255 | dprintk( | ||
| 256 | KERN_INFO " login_type = " | ||
| 257 | "TF_LOGIN_GROUP\n"); | ||
| 258 | break; | ||
| 259 | case TF_LOGIN_APPLICATION: | ||
| 260 | dprintk( | ||
| 261 | KERN_INFO " login_type = " | ||
| 262 | "TF_LOGIN_APPLICATION\n"); | ||
| 263 | break; | ||
| 264 | case TF_LOGIN_APPLICATION_USER: | ||
| 265 | dprintk( | ||
| 266 | KERN_INFO " login_type = " | ||
| 267 | "TF_LOGIN_APPLICATION_USER\n"); | ||
| 268 | break; | ||
| 269 | case TF_LOGIN_APPLICATION_GROUP: | ||
| 270 | dprintk( | ||
| 271 | KERN_INFO " login_type = " | ||
| 272 | "TF_LOGIN_APPLICATION_GROUP\n"); | ||
| 273 | break; | ||
| 274 | case TF_LOGIN_AUTHENTICATION: | ||
| 275 | dprintk( | ||
| 276 | KERN_INFO " login_type = " | ||
| 277 | "TF_LOGIN_AUTHENTICATION\n"); | ||
| 278 | break; | ||
| 279 | case TF_LOGIN_PRIVILEGED: | ||
| 280 | dprintk( | ||
| 281 | KERN_INFO " login_type = " | ||
| 282 | "TF_LOGIN_PRIVILEGED\n"); | ||
| 283 | break; | ||
| 284 | case TF_LOGIN_PRIVILEGED_KERNEL: | ||
| 285 | dprintk( | ||
| 286 | KERN_INFO " login_type = " | ||
| 287 | "TF_LOGIN_PRIVILEGED_KERNEL\n"); | ||
| 288 | break; | ||
| 289 | default: | ||
| 290 | dprintk( | ||
| 291 | KERN_ERR " login_type = " | ||
| 292 | "0x%08X (Unknown login type)\n", | ||
| 293 | command->open_client_session.login_type); | ||
| 294 | break; | ||
| 295 | } | ||
| 296 | |||
| 297 | dprintk( | ||
| 298 | KERN_INFO " login_data = "); | ||
| 299 | for (i = 0; i < 20; i++) | ||
| 300 | dprintk( | ||
| 301 | KERN_INFO "%d", | ||
| 302 | command->open_client_session. | ||
| 303 | login_data[i]); | ||
| 304 | dprintk("\n"); | ||
| 305 | break; | ||
| 306 | |||
| 307 | case TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION: | ||
| 308 | dprintk(KERN_INFO | ||
| 309 | " message_size = 0x%02X\n" | ||
| 310 | " message_type = 0x%02X " | ||
| 311 | "TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION\n" | ||
| 312 | " operation_id = 0x%08X\n" | ||
| 313 | " device_context = 0x%08X\n" | ||
| 314 | " client_session = 0x%08X\n", | ||
| 315 | command->header.message_size, | ||
| 316 | command->header.message_type, | ||
| 317 | command->header.operation_id, | ||
| 318 | command->close_client_session.device_context, | ||
| 319 | command->close_client_session.client_session | ||
| 320 | ); | ||
| 321 | break; | ||
| 322 | |||
| 323 | case TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY: | ||
| 324 | dprintk(KERN_INFO | ||
| 325 | " message_size = 0x%02X\n" | ||
| 326 | " message_type = 0x%02X " | ||
| 327 | "TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY\n" | ||
| 328 | " memory_flags = 0x%04X\n" | ||
| 329 | " operation_id = 0x%08X\n" | ||
| 330 | " device_context = 0x%08X\n" | ||
| 331 | " block_id = 0x%08X\n" | ||
| 332 | " shared_mem_size = 0x%08X\n" | ||
| 333 | " shared_mem_start_offset = 0x%08X\n" | ||
| 334 | " shared_mem_descriptors[0] = 0x%08X\n" | ||
| 335 | " shared_mem_descriptors[1] = 0x%08X\n" | ||
| 336 | " shared_mem_descriptors[2] = 0x%08X\n" | ||
| 337 | " shared_mem_descriptors[3] = 0x%08X\n" | ||
| 338 | " shared_mem_descriptors[4] = 0x%08X\n" | ||
| 339 | " shared_mem_descriptors[5] = 0x%08X\n" | ||
| 340 | " shared_mem_descriptors[6] = 0x%08X\n" | ||
| 341 | " shared_mem_descriptors[7] = 0x%08X\n", | ||
| 342 | command->header.message_size, | ||
| 343 | command->header.message_type, | ||
| 344 | command->register_shared_memory.memory_flags, | ||
| 345 | command->header.operation_id, | ||
| 346 | command->register_shared_memory.device_context, | ||
| 347 | command->register_shared_memory.block_id, | ||
| 348 | command->register_shared_memory.shared_mem_size, | ||
| 349 | command->register_shared_memory. | ||
| 350 | shared_mem_start_offset, | ||
| 351 | command->register_shared_memory. | ||
| 352 | shared_mem_descriptors[0], | ||
| 353 | command->register_shared_memory. | ||
| 354 | shared_mem_descriptors[1], | ||
| 355 | command->register_shared_memory. | ||
| 356 | shared_mem_descriptors[2], | ||
| 357 | command->register_shared_memory. | ||
| 358 | shared_mem_descriptors[3], | ||
| 359 | command->register_shared_memory. | ||
| 360 | shared_mem_descriptors[4], | ||
| 361 | command->register_shared_memory. | ||
| 362 | shared_mem_descriptors[5], | ||
| 363 | command->register_shared_memory. | ||
| 364 | shared_mem_descriptors[6], | ||
| 365 | command->register_shared_memory. | ||
| 366 | shared_mem_descriptors[7]); | ||
| 367 | break; | ||
| 368 | |||
| 369 | case TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY: | ||
| 370 | dprintk(KERN_INFO | ||
| 371 | " message_size = 0x%02X\n" | ||
| 372 | " message_type = 0x%02X " | ||
| 373 | "TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY\n" | ||
| 374 | " operation_id = 0x%08X\n" | ||
| 375 | " device_context = 0x%08X\n" | ||
| 376 | " block = 0x%08X\n", | ||
| 377 | command->header.message_size, | ||
| 378 | command->header.message_type, | ||
| 379 | command->header.operation_id, | ||
| 380 | command->release_shared_memory.device_context, | ||
| 381 | command->release_shared_memory.block); | ||
| 382 | break; | ||
| 383 | |||
| 384 | case TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND: | ||
| 385 | dprintk(KERN_INFO | ||
| 386 | " message_size = 0x%02X\n" | ||
| 387 | " message_type = 0x%02X " | ||
| 388 | "TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND\n" | ||
| 389 | " param_types = 0x%04X\n" | ||
| 390 | " operation_id = 0x%08X\n" | ||
| 391 | " device_context = 0x%08X\n" | ||
| 392 | " client_session = 0x%08X\n" | ||
| 393 | " timeout = 0x%016llX\n" | ||
| 394 | " cancellation_id = 0x%08X\n" | ||
| 395 | " client_command_identifier = 0x%08X\n", | ||
| 396 | command->header.message_size, | ||
| 397 | command->header.message_type, | ||
| 398 | command->invoke_client_command.param_types, | ||
| 399 | command->header.operation_id, | ||
| 400 | command->invoke_client_command.device_context, | ||
| 401 | command->invoke_client_command.client_session, | ||
| 402 | command->invoke_client_command.timeout, | ||
| 403 | command->invoke_client_command.cancellation_id, | ||
| 404 | command->invoke_client_command. | ||
| 405 | client_command_identifier | ||
| 406 | ); | ||
| 407 | |||
| 408 | for (i = 0; i < 4; i++) { | ||
| 409 | uint32_t *param = (uint32_t *) &command-> | ||
| 410 | open_client_session.params[i]; | ||
| 411 | dprintk(KERN_INFO " params[%d] = " | ||
| 412 | "0x%08X:0x%08X:0x%08X\n", i, | ||
| 413 | param[0], param[1], param[2]); | ||
| 414 | } | ||
| 415 | break; | ||
| 416 | |||
| 417 | case TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND: | ||
| 418 | dprintk(KERN_INFO | ||
| 419 | " message_size = 0x%02X\n" | ||
| 420 | " message_type = 0x%02X " | ||
| 421 | "TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND\n" | ||
| 422 | " operation_id = 0x%08X\n" | ||
| 423 | " device_context = 0x%08X\n" | ||
| 424 | " client_session = 0x%08X\n", | ||
| 425 | command->header.message_size, | ||
| 426 | command->header.message_type, | ||
| 427 | command->header.operation_id, | ||
| 428 | command->cancel_client_operation.device_context, | ||
| 429 | command->cancel_client_operation.client_session); | ||
| 430 | break; | ||
| 431 | |||
| 432 | case TF_MESSAGE_TYPE_MANAGEMENT: | ||
| 433 | dprintk(KERN_INFO | ||
| 434 | " message_size = 0x%02X\n" | ||
| 435 | " message_type = 0x%02X " | ||
| 436 | "TF_MESSAGE_TYPE_MANAGEMENT\n" | ||
| 437 | " operation_id = 0x%08X\n" | ||
| 438 | " command = 0x%08X\n" | ||
| 439 | " w3b_size = 0x%08X\n" | ||
| 440 | " w3b_start_offset = 0x%08X\n", | ||
| 441 | command->header.message_size, | ||
| 442 | command->header.message_type, | ||
| 443 | command->header.operation_id, | ||
| 444 | command->management.command, | ||
| 445 | command->management.w3b_size, | ||
| 446 | command->management.w3b_start_offset); | ||
| 447 | break; | ||
| 448 | |||
| 449 | default: | ||
| 450 | dprintk( | ||
| 451 | KERN_ERR " message_type = 0x%08X " | ||
| 452 | "(Unknown message type)\n", | ||
| 453 | command->header.message_type); | ||
| 454 | break; | ||
| 455 | } | ||
| 456 | } | ||
| 457 | |||
| 458 | |||
| 459 | /* | ||
| 460 | * Dump the specified SChannel answer using dprintk. | ||
| 461 | */ | ||
| 462 | void tf_dump_answer(union tf_answer *answer) | ||
| 463 | { | ||
| 464 | u32 i; | ||
| 465 | dprintk( | ||
| 466 | KERN_INFO "answer@%p:\n", | ||
| 467 | answer); | ||
| 468 | |||
| 469 | switch (answer->header.message_type) { | ||
| 470 | case TF_MESSAGE_TYPE_CREATE_DEVICE_CONTEXT: | ||
| 471 | dprintk(KERN_INFO | ||
| 472 | " message_size = 0x%02X\n" | ||
| 473 | " message_type = 0x%02X " | ||
| 474 | "tf_answer_create_device_context\n" | ||
| 475 | " operation_id = 0x%08X\n" | ||
| 476 | " error_code = 0x%08X\n" | ||
| 477 | " device_context = 0x%08X\n", | ||
| 478 | answer->header.message_size, | ||
| 479 | answer->header.message_type, | ||
| 480 | answer->header.operation_id, | ||
| 481 | answer->create_device_context.error_code, | ||
| 482 | answer->create_device_context.device_context); | ||
| 483 | break; | ||
| 484 | |||
| 485 | case TF_MESSAGE_TYPE_DESTROY_DEVICE_CONTEXT: | ||
| 486 | dprintk(KERN_INFO | ||
| 487 | " message_size = 0x%02X\n" | ||
| 488 | " message_type = 0x%02X " | ||
| 489 | "ANSWER_DESTROY_DEVICE_CONTEXT\n" | ||
| 490 | " operation_id = 0x%08X\n" | ||
| 491 | " error_code = 0x%08X\n" | ||
| 492 | " device_context_id = 0x%08X\n", | ||
| 493 | answer->header.message_size, | ||
| 494 | answer->header.message_type, | ||
| 495 | answer->header.operation_id, | ||
| 496 | answer->destroy_device_context.error_code, | ||
| 497 | answer->destroy_device_context.device_context_id); | ||
| 498 | break; | ||
| 499 | |||
| 500 | |||
| 501 | case TF_MESSAGE_TYPE_OPEN_CLIENT_SESSION: | ||
| 502 | dprintk(KERN_INFO | ||
| 503 | " message_size = 0x%02X\n" | ||
| 504 | " message_type = 0x%02X " | ||
| 505 | "tf_answer_open_client_session\n" | ||
| 506 | " error_origin = 0x%02X\n" | ||
| 507 | " operation_id = 0x%08X\n" | ||
| 508 | " error_code = 0x%08X\n" | ||
| 509 | " client_session = 0x%08X\n", | ||
| 510 | answer->header.message_size, | ||
| 511 | answer->header.message_type, | ||
| 512 | answer->open_client_session.error_origin, | ||
| 513 | answer->header.operation_id, | ||
| 514 | answer->open_client_session.error_code, | ||
| 515 | answer->open_client_session.client_session); | ||
| 516 | for (i = 0; i < 4; i++) { | ||
| 517 | dprintk(KERN_INFO " answers[%d]=0x%08X:0x%08X\n", | ||
| 518 | i, | ||
| 519 | answer->open_client_session.answers[i]. | ||
| 520 | value.a, | ||
| 521 | answer->open_client_session.answers[i]. | ||
| 522 | value.b); | ||
| 523 | } | ||
| 524 | break; | ||
| 525 | |||
| 526 | case TF_MESSAGE_TYPE_CLOSE_CLIENT_SESSION: | ||
| 527 | dprintk(KERN_INFO | ||
| 528 | " message_size = 0x%02X\n" | ||
| 529 | " message_type = 0x%02X " | ||
| 530 | "ANSWER_CLOSE_CLIENT_SESSION\n" | ||
| 531 | " operation_id = 0x%08X\n" | ||
| 532 | " error_code = 0x%08X\n", | ||
| 533 | answer->header.message_size, | ||
| 534 | answer->header.message_type, | ||
| 535 | answer->header.operation_id, | ||
| 536 | answer->close_client_session.error_code); | ||
| 537 | break; | ||
| 538 | |||
| 539 | case TF_MESSAGE_TYPE_REGISTER_SHARED_MEMORY: | ||
| 540 | dprintk(KERN_INFO | ||
| 541 | " message_size = 0x%02X\n" | ||
| 542 | " message_type = 0x%02X " | ||
| 543 | "tf_answer_register_shared_memory\n" | ||
| 544 | " operation_id = 0x%08X\n" | ||
| 545 | " error_code = 0x%08X\n" | ||
| 546 | " block = 0x%08X\n", | ||
| 547 | answer->header.message_size, | ||
| 548 | answer->header.message_type, | ||
| 549 | answer->header.operation_id, | ||
| 550 | answer->register_shared_memory.error_code, | ||
| 551 | answer->register_shared_memory.block); | ||
| 552 | break; | ||
| 553 | |||
| 554 | case TF_MESSAGE_TYPE_RELEASE_SHARED_MEMORY: | ||
| 555 | dprintk(KERN_INFO | ||
| 556 | " message_size = 0x%02X\n" | ||
| 557 | " message_type = 0x%02X " | ||
| 558 | "ANSWER_RELEASE_SHARED_MEMORY\n" | ||
| 559 | " operation_id = 0x%08X\n" | ||
| 560 | " error_code = 0x%08X\n" | ||
| 561 | " block_id = 0x%08X\n", | ||
| 562 | answer->header.message_size, | ||
| 563 | answer->header.message_type, | ||
| 564 | answer->header.operation_id, | ||
| 565 | answer->release_shared_memory.error_code, | ||
| 566 | answer->release_shared_memory.block_id); | ||
| 567 | break; | ||
| 568 | |||
| 569 | case TF_MESSAGE_TYPE_INVOKE_CLIENT_COMMAND: | ||
| 570 | dprintk(KERN_INFO | ||
| 571 | " message_size = 0x%02X\n" | ||
| 572 | " message_type = 0x%02X " | ||
| 573 | "tf_answer_invoke_client_command\n" | ||
| 574 | " error_origin = 0x%02X\n" | ||
| 575 | " operation_id = 0x%08X\n" | ||
| 576 | " error_code = 0x%08X\n", | ||
| 577 | answer->header.message_size, | ||
| 578 | answer->header.message_type, | ||
| 579 | answer->invoke_client_command.error_origin, | ||
| 580 | answer->header.operation_id, | ||
| 581 | answer->invoke_client_command.error_code | ||
| 582 | ); | ||
| 583 | for (i = 0; i < 4; i++) { | ||
| 584 | dprintk(KERN_INFO " answers[%d]=0x%08X:0x%08X\n", | ||
| 585 | i, | ||
| 586 | answer->invoke_client_command.answers[i]. | ||
| 587 | value.a, | ||
| 588 | answer->invoke_client_command.answers[i]. | ||
| 589 | value.b); | ||
| 590 | } | ||
| 591 | break; | ||
| 592 | |||
| 593 | case TF_MESSAGE_TYPE_CANCEL_CLIENT_COMMAND: | ||
| 594 | dprintk(KERN_INFO | ||
| 595 | " message_size = 0x%02X\n" | ||
| 596 | " message_type = 0x%02X " | ||
| 597 | "TF_ANSWER_CANCEL_CLIENT_COMMAND\n" | ||
| 598 | " operation_id = 0x%08X\n" | ||
| 599 | " error_code = 0x%08X\n", | ||
| 600 | answer->header.message_size, | ||
| 601 | answer->header.message_type, | ||
| 602 | answer->header.operation_id, | ||
| 603 | answer->cancel_client_operation.error_code); | ||
| 604 | break; | ||
| 605 | |||
| 606 | case TF_MESSAGE_TYPE_MANAGEMENT: | ||
| 607 | dprintk(KERN_INFO | ||
| 608 | " message_size = 0x%02X\n" | ||
| 609 | " message_type = 0x%02X " | ||
| 610 | "TF_MESSAGE_TYPE_MANAGEMENT\n" | ||
| 611 | " operation_id = 0x%08X\n" | ||
| 612 | " error_code = 0x%08X\n", | ||
| 613 | answer->header.message_size, | ||
| 614 | answer->header.message_type, | ||
| 615 | answer->header.operation_id, | ||
| 616 | answer->header.error_code); | ||
| 617 | break; | ||
| 618 | |||
| 619 | default: | ||
| 620 | dprintk( | ||
| 621 | KERN_ERR " message_type = 0x%02X " | ||
| 622 | "(Unknown message type)\n", | ||
| 623 | answer->header.message_type); | ||
| 624 | break; | ||
| 625 | |||
| 626 | } | ||
| 627 | } | ||
| 628 | |||
| 629 | #endif /* defined(TF_DRIVER_DEBUG_SUPPORT) */ | ||
| 630 | |||
| 631 | /*---------------------------------------------------------------------------- | ||
| 632 | * SHA-1 implementation | ||
| 633 | * This is taken from the Linux kernel source crypto/sha1.c | ||
| 634 | *----------------------------------------------------------------------------*/ | ||
| 635 | |||
| 636 | struct sha1_ctx { | ||
| 637 | u64 count; | ||
| 638 | u32 state[5]; | ||
| 639 | u8 buffer[64]; | ||
| 640 | }; | ||
| 641 | |||
| 642 | static inline u32 rol(u32 value, u32 bits) | ||
| 643 | { | ||
| 644 | return ((value) << (bits)) | ((value) >> (32 - (bits))); | ||
| 645 | } | ||
| 646 | |||
| 647 | /* blk0() and blk() perform the initial expand. */ | ||
| 648 | /* I got the idea of expanding during the round function from SSLeay */ | ||
| 649 | #define blk0(i) block32[i] | ||
| 650 | |||
| 651 | #define blk(i) (block32[i & 15] = rol( \ | ||
| 652 | block32[(i + 13) & 15] ^ block32[(i + 8) & 15] ^ \ | ||
| 653 | block32[(i + 2) & 15] ^ block32[i & 15], 1)) | ||
| 654 | |||
| 655 | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ | ||
| 656 | #define R0(v, w, x, y, z, i) do { \ | ||
| 657 | z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ | ||
| 658 | w = rol(w, 30); } while (0) | ||
| 659 | |||
| 660 | #define R1(v, w, x, y, z, i) do { \ | ||
| 661 | z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ | ||
| 662 | w = rol(w, 30); } while (0) | ||
| 663 | |||
| 664 | #define R2(v, w, x, y, z, i) do { \ | ||
| 665 | z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ | ||
| 666 | w = rol(w, 30); } while (0) | ||
| 667 | |||
| 668 | #define R3(v, w, x, y, z, i) do { \ | ||
| 669 | z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ | ||
| 670 | w = rol(w, 30); } while (0) | ||
| 671 | |||
| 672 | #define R4(v, w, x, y, z, i) do { \ | ||
| 673 | z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ | ||
| 674 | w = rol(w, 30); } while (0) | ||
| 675 | |||
| 676 | |||
| 677 | /* Hash a single 512-bit block. This is the core of the algorithm. */ | ||
| 678 | static void sha1_transform(u32 *state, const u8 *in) | ||
| 679 | { | ||
| 680 | u32 a, b, c, d, e; | ||
| 681 | u32 block32[16]; | ||
| 682 | |||
| 683 | /* convert/copy data to workspace */ | ||
| 684 | for (a = 0; a < sizeof(block32)/sizeof(u32); a++) | ||
| 685 | block32[a] = ((u32) in[4 * a]) << 24 | | ||
| 686 | ((u32) in[4 * a + 1]) << 16 | | ||
| 687 | ((u32) in[4 * a + 2]) << 8 | | ||
| 688 | ((u32) in[4 * a + 3]); | ||
| 689 | |||
| 690 | /* Copy context->state[] to working vars */ | ||
| 691 | a = state[0]; | ||
| 692 | b = state[1]; | ||
| 693 | c = state[2]; | ||
| 694 | d = state[3]; | ||
| 695 | e = state[4]; | ||
| 696 | |||
| 697 | /* 4 rounds of 20 operations each. Loop unrolled. */ | ||
| 698 | R0(a, b, c, d, e, 0); R0(e, a, b, c, d, 1); | ||
| 699 | R0(d, e, a, b, c, 2); R0(c, d, e, a, b, 3); | ||
| 700 | R0(b, c, d, e, a, 4); R0(a, b, c, d, e, 5); | ||
| 701 | R0(e, a, b, c, d, 6); R0(d, e, a, b, c, 7); | ||
| 702 | R0(c, d, e, a, b, 8); R0(b, c, d, e, a, 9); | ||
| 703 | R0(a, b, c, d, e, 10); R0(e, a, b, c, d, 11); | ||
| 704 | R0(d, e, a, b, c, 12); R0(c, d, e, a, b, 13); | ||
| 705 | R0(b, c, d, e, a, 14); R0(a, b, c, d, e, 15); | ||
| 706 | |||
| 707 | R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); | ||
| 708 | R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19); | ||
| 709 | |||
| 710 | R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); | ||
| 711 | R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23); | ||
| 712 | R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); | ||
| 713 | R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27); | ||
| 714 | R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); | ||
| 715 | R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31); | ||
| 716 | R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); | ||
| 717 | R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35); | ||
| 718 | R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); | ||
| 719 | R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39); | ||
| 720 | |||
| 721 | R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); | ||
| 722 | R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43); | ||
| 723 | R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); | ||
| 724 | R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47); | ||
| 725 | R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); | ||
| 726 | R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51); | ||
| 727 | R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); | ||
| 728 | R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55); | ||
| 729 | R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); | ||
| 730 | R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59); | ||
| 731 | |||
| 732 | R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); | ||
| 733 | R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63); | ||
| 734 | R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); | ||
| 735 | R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67); | ||
| 736 | R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); | ||
| 737 | R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71); | ||
| 738 | R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); | ||
| 739 | R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75); | ||
| 740 | R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); | ||
| 741 | R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79); | ||
| 742 | |||
| 743 | /* Add the working vars back into context.state[] */ | ||
| 744 | state[0] += a; | ||
| 745 | state[1] += b; | ||
| 746 | state[2] += c; | ||
| 747 | state[3] += d; | ||
| 748 | state[4] += e; | ||
| 749 | /* Wipe variables */ | ||
| 750 | a = b = c = d = e = 0; | ||
| 751 | memset(block32, 0x00, sizeof(block32)); | ||
| 752 | } | ||
| 753 | |||
| 754 | |||
| 755 | static void sha1_init(void *ctx) | ||
| 756 | { | ||
| 757 | struct sha1_ctx *sctx = ctx; | ||
| 758 | static const struct sha1_ctx initstate = { | ||
| 759 | 0, | ||
| 760 | { 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 }, | ||
| 761 | { 0, } | ||
| 762 | }; | ||
| 763 | |||
| 764 | *sctx = initstate; | ||
| 765 | } | ||
| 766 | |||
| 767 | |||
| 768 | static void sha1_update(void *ctx, const u8 *data, unsigned int len) | ||
| 769 | { | ||
| 770 | struct sha1_ctx *sctx = ctx; | ||
| 771 | unsigned int i, j; | ||
| 772 | |||
| 773 | j = (sctx->count >> 3) & 0x3f; | ||
| 774 | sctx->count += len << 3; | ||
| 775 | |||
| 776 | if ((j + len) > 63) { | ||
| 777 | memcpy(&sctx->buffer[j], data, (i = 64 - j)); | ||
| 778 | sha1_transform(sctx->state, sctx->buffer); | ||
| 779 | for ( ; i + 63 < len; i += 64) | ||
| 780 | sha1_transform(sctx->state, &data[i]); | ||
| 781 | j = 0; | ||
| 782 | } else | ||
| 783 | i = 0; | ||
| 784 | memcpy(&sctx->buffer[j], &data[i], len - i); | ||
| 785 | } | ||
| 786 | |||
| 787 | |||
| 788 | /* Add padding and return the message digest. */ | ||
| 789 | static void sha1_final(void *ctx, u8 *out) | ||
| 790 | { | ||
| 791 | struct sha1_ctx *sctx = ctx; | ||
| 792 | u32 i, j, index, padlen; | ||
| 793 | u64 t; | ||
| 794 | u8 bits[8] = { 0, }; | ||
| 795 | static const u8 padding[64] = { 0x80, }; | ||
| 796 | |||
| 797 | t = sctx->count; | ||
| 798 | bits[7] = 0xff & t; t >>= 8; | ||
| 799 | bits[6] = 0xff & t; t >>= 8; | ||
| 800 | bits[5] = 0xff & t; t >>= 8; | ||
| 801 | bits[4] = 0xff & t; t >>= 8; | ||
| 802 | bits[3] = 0xff & t; t >>= 8; | ||
| 803 | bits[2] = 0xff & t; t >>= 8; | ||
| 804 | bits[1] = 0xff & t; t >>= 8; | ||
| 805 | bits[0] = 0xff & t; | ||
| 806 | |||
| 807 | /* Pad out to 56 mod 64 */ | ||
| 808 | index = (sctx->count >> 3) & 0x3f; | ||
| 809 | padlen = (index < 56) ? (56 - index) : ((64+56) - index); | ||
| 810 | sha1_update(sctx, padding, padlen); | ||
| 811 | |||
| 812 | /* Append length */ | ||
| 813 | sha1_update(sctx, bits, sizeof(bits)); | ||
| 814 | |||
| 815 | /* Store state in digest */ | ||
| 816 | for (i = j = 0; i < 5; i++, j += 4) { | ||
| 817 | u32 t2 = sctx->state[i]; | ||
| 818 | out[j+3] = t2 & 0xff; t2 >>= 8; | ||
| 819 | out[j+2] = t2 & 0xff; t2 >>= 8; | ||
| 820 | out[j+1] = t2 & 0xff; t2 >>= 8; | ||
| 821 | out[j] = t2 & 0xff; | ||
| 822 | } | ||
| 823 | |||
| 824 | /* Wipe context */ | ||
| 825 | memset(sctx, 0, sizeof(*sctx)); | ||
| 826 | } | ||
| 827 | |||
| 828 | |||
| 829 | |||
| 830 | |||
| 831 | /*---------------------------------------------------------------------------- | ||
| 832 | * Process identification | ||
| 833 | *----------------------------------------------------------------------------*/ | ||
| 834 | |||
| 835 | /* This function generates a processes hash table for authentication */ | ||
| 836 | int tf_get_current_process_hash(void *hash) | ||
| 837 | { | ||
| 838 | int result = 0; | ||
| 839 | void *buffer; | ||
| 840 | struct mm_struct *mm; | ||
| 841 | struct vm_area_struct *vma; | ||
| 842 | |||
| 843 | buffer = internal_kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 844 | if (buffer == NULL) { | ||
| 845 | dprintk( | ||
| 846 | KERN_ERR "tf_get_current_process_hash:" | ||
| 847 | " Out of memory for buffer!\n"); | ||
| 848 | return -ENOMEM; | ||
| 849 | } | ||
| 850 | |||
| 851 | mm = current->mm; | ||
| 852 | |||
| 853 | down_read(&(mm->mmap_sem)); | ||
| 854 | for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) { | ||
| 855 | if ((vma->vm_flags & VM_EXECUTABLE) != 0 && vma->vm_file | ||
| 856 | != NULL) { | ||
| 857 | struct dentry *dentry; | ||
| 858 | unsigned long start; | ||
| 859 | unsigned long cur; | ||
| 860 | unsigned long end; | ||
| 861 | struct sha1_ctx sha1; | ||
| 862 | |||
| 863 | dentry = dget(vma->vm_file->f_dentry); | ||
| 864 | |||
| 865 | dprintk( | ||
| 866 | KERN_DEBUG "tf_get_current_process_hash: " | ||
| 867 | "Found executable VMA for inode %lu " | ||
| 868 | "(%lu bytes).\n", | ||
| 869 | dentry->d_inode->i_ino, | ||
| 870 | (unsigned long) (dentry->d_inode-> | ||
| 871 | i_size)); | ||
| 872 | |||
| 873 | start = do_mmap(vma->vm_file, 0, | ||
| 874 | dentry->d_inode->i_size, | ||
| 875 | PROT_READ | PROT_WRITE | PROT_EXEC, | ||
| 876 | MAP_PRIVATE, 0); | ||
| 877 | if (start < 0) { | ||
| 878 | dprintk( | ||
| 879 | KERN_ERR "tf_get_current_process_hash" | ||
| 880 | "Hash: do_mmap failed (error %d)!\n", | ||
| 881 | (int) start); | ||
| 882 | dput(dentry); | ||
| 883 | result = -EFAULT; | ||
| 884 | goto vma_out; | ||
| 885 | } | ||
| 886 | |||
| 887 | end = start + dentry->d_inode->i_size; | ||
| 888 | |||
| 889 | sha1_init(&sha1); | ||
| 890 | cur = start; | ||
| 891 | while (cur < end) { | ||
| 892 | unsigned long chunk; | ||
| 893 | |||
| 894 | chunk = end - cur; | ||
| 895 | if (chunk > PAGE_SIZE) | ||
| 896 | chunk = PAGE_SIZE; | ||
| 897 | if (copy_from_user(buffer, (const void *) cur, | ||
| 898 | chunk) != 0) { | ||
| 899 | dprintk( | ||
| 900 | KERN_ERR "tf_get_current_" | ||
| 901 | "process_hash: copy_from_user " | ||
| 902 | "failed!\n"); | ||
| 903 | result = -EINVAL; | ||
| 904 | (void) do_munmap(mm, start, | ||
| 905 | dentry->d_inode->i_size); | ||
| 906 | dput(dentry); | ||
| 907 | goto vma_out; | ||
| 908 | } | ||
| 909 | sha1_update(&sha1, buffer, chunk); | ||
| 910 | cur += chunk; | ||
| 911 | } | ||
| 912 | sha1_final(&sha1, hash); | ||
| 913 | result = 0; | ||
| 914 | |||
| 915 | (void) do_munmap(mm, start, dentry->d_inode->i_size); | ||
| 916 | dput(dentry); | ||
| 917 | break; | ||
| 918 | } | ||
| 919 | } | ||
| 920 | vma_out: | ||
| 921 | up_read(&(mm->mmap_sem)); | ||
| 922 | |||
| 923 | internal_kfree(buffer); | ||
| 924 | |||
| 925 | if (result == -ENOENT) | ||
| 926 | dprintk( | ||
| 927 | KERN_ERR "tf_get_current_process_hash: " | ||
| 928 | "No executable VMA found for process!\n"); | ||
| 929 | return result; | ||
| 930 | } | ||
| 931 | |||
| 932 | #ifndef CONFIG_ANDROID | ||
| 933 | /* This function hashes the path of the current application. | ||
| 934 | * If data = NULL ,nothing else is added to the hash | ||
| 935 | else add data to the hash | ||
| 936 | */ | ||
| 937 | int tf_hash_application_path_and_data(char *buffer, void *data, | ||
| 938 | u32 data_len) | ||
| 939 | { | ||
| 940 | int result = -ENOENT; | ||
| 941 | char *tmp = NULL; | ||
| 942 | struct mm_struct *mm; | ||
| 943 | struct vm_area_struct *vma; | ||
| 944 | |||
| 945 | tmp = internal_kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
| 946 | if (tmp == NULL) { | ||
| 947 | result = -ENOMEM; | ||
| 948 | goto end; | ||
| 949 | } | ||
| 950 | |||
| 951 | mm = current->mm; | ||
| 952 | |||
| 953 | down_read(&(mm->mmap_sem)); | ||
| 954 | for (vma = mm->mmap; vma != NULL; vma = vma->vm_next) { | ||
| 955 | if ((vma->vm_flags & VM_EXECUTABLE) != 0 | ||
| 956 | && vma->vm_file != NULL) { | ||
| 957 | struct path *path; | ||
| 958 | char *endpath; | ||
| 959 | size_t pathlen; | ||
| 960 | struct sha1_ctx sha1; | ||
| 961 | u8 hash[SHA1_DIGEST_SIZE]; | ||
| 962 | |||
| 963 | path = &vma->vm_file->f_path; | ||
| 964 | |||
| 965 | endpath = d_path(path, tmp, PAGE_SIZE); | ||
| 966 | if (IS_ERR(path)) { | ||
| 967 | result = PTR_ERR(endpath); | ||
| 968 | up_read(&(mm->mmap_sem)); | ||
| 969 | goto end; | ||
| 970 | } | ||
| 971 | pathlen = (tmp + PAGE_SIZE) - endpath; | ||
| 972 | |||
| 973 | #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT | ||
| 974 | { | ||
| 975 | char *c; | ||
| 976 | dprintk(KERN_DEBUG "current process path = "); | ||
| 977 | for (c = endpath; | ||
| 978 | c < tmp + PAGE_SIZE; | ||
| 979 | c++) | ||
| 980 | dprintk("%c", *c); | ||
| 981 | |||
| 982 | dprintk(", uid=%d, euid=%d\n", current_uid(), | ||
| 983 | current_euid()); | ||
| 984 | } | ||
| 985 | #endif /* defined(CONFIG_TF_DRIVER_DEBUG_SUPPORT) */ | ||
| 986 | |||
| 987 | sha1_init(&sha1); | ||
| 988 | sha1_update(&sha1, endpath, pathlen); | ||
| 989 | if (data != NULL) { | ||
| 990 | dprintk(KERN_INFO "current process path: " | ||
| 991 | "Hashing additional data\n"); | ||
| 992 | sha1_update(&sha1, data, data_len); | ||
| 993 | } | ||
| 994 | sha1_final(&sha1, hash); | ||
| 995 | memcpy(buffer, hash, sizeof(hash)); | ||
| 996 | |||
| 997 | result = 0; | ||
| 998 | |||
| 999 | break; | ||
| 1000 | } | ||
| 1001 | } | ||
| 1002 | up_read(&(mm->mmap_sem)); | ||
| 1003 | |||
| 1004 | end: | ||
| 1005 | if (tmp != NULL) | ||
| 1006 | internal_kfree(tmp); | ||
| 1007 | |||
| 1008 | return result; | ||
| 1009 | } | ||
| 1010 | #endif /* !CONFIG_ANDROID */ | ||
| 1011 | |||
| 1012 | void *internal_kmalloc(size_t size, int priority) | ||
| 1013 | { | ||
| 1014 | void *ptr; | ||
| 1015 | struct tf_device *dev = tf_get_device(); | ||
| 1016 | |||
| 1017 | ptr = kmalloc(size, priority); | ||
| 1018 | |||
| 1019 | if (ptr != NULL) | ||
| 1020 | atomic_inc( | ||
| 1021 | &dev->stats.stat_memories_allocated); | ||
| 1022 | |||
| 1023 | return ptr; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | void internal_kfree(void *ptr) | ||
| 1027 | { | ||
| 1028 | struct tf_device *dev = tf_get_device(); | ||
| 1029 | |||
| 1030 | if (ptr != NULL) | ||
| 1031 | atomic_dec( | ||
| 1032 | &dev->stats.stat_memories_allocated); | ||
| 1033 | return kfree(ptr); | ||
| 1034 | } | ||
| 1035 | |||
| 1036 | void internal_vunmap(void *ptr) | ||
| 1037 | { | ||
| 1038 | struct tf_device *dev = tf_get_device(); | ||
| 1039 | |||
| 1040 | if (ptr != NULL) | ||
| 1041 | atomic_dec( | ||
| 1042 | &dev->stats.stat_memories_allocated); | ||
| 1043 | |||
| 1044 | vunmap((void *) (((unsigned int)ptr) & 0xFFFFF000)); | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | void *internal_vmalloc(size_t size) | ||
| 1048 | { | ||
| 1049 | void *ptr; | ||
| 1050 | struct tf_device *dev = tf_get_device(); | ||
| 1051 | |||
| 1052 | ptr = vmalloc(size); | ||
| 1053 | |||
| 1054 | if (ptr != NULL) | ||
| 1055 | atomic_inc( | ||
| 1056 | &dev->stats.stat_memories_allocated); | ||
| 1057 | |||
| 1058 | return ptr; | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | void internal_vfree(void *ptr) | ||
| 1062 | { | ||
| 1063 | struct tf_device *dev = tf_get_device(); | ||
| 1064 | |||
| 1065 | if (ptr != NULL) | ||
| 1066 | atomic_dec( | ||
| 1067 | &dev->stats.stat_memories_allocated); | ||
| 1068 | return vfree(ptr); | ||
| 1069 | } | ||
| 1070 | |||
| 1071 | unsigned long internal_get_zeroed_page(int priority) | ||
| 1072 | { | ||
| 1073 | unsigned long result; | ||
| 1074 | struct tf_device *dev = tf_get_device(); | ||
| 1075 | |||
| 1076 | result = get_zeroed_page(priority); | ||
| 1077 | |||
| 1078 | if (result != 0) | ||
| 1079 | atomic_inc(&dev->stats. | ||
| 1080 | stat_pages_allocated); | ||
| 1081 | |||
| 1082 | return result; | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | void internal_free_page(unsigned long addr) | ||
| 1086 | { | ||
| 1087 | struct tf_device *dev = tf_get_device(); | ||
| 1088 | |||
| 1089 | if (addr != 0) | ||
| 1090 | atomic_dec( | ||
| 1091 | &dev->stats.stat_pages_allocated); | ||
| 1092 | return free_page(addr); | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | int internal_get_user_pages( | ||
| 1096 | struct task_struct *tsk, | ||
| 1097 | struct mm_struct *mm, | ||
| 1098 | unsigned long start, | ||
| 1099 | int len, | ||
| 1100 | int write, | ||
| 1101 | int force, | ||
| 1102 | struct page **pages, | ||
| 1103 | struct vm_area_struct **vmas) | ||
| 1104 | { | ||
| 1105 | int result; | ||
| 1106 | struct tf_device *dev = tf_get_device(); | ||
| 1107 | |||
| 1108 | result = get_user_pages( | ||
| 1109 | tsk, | ||
| 1110 | mm, | ||
| 1111 | start, | ||
| 1112 | len, | ||
| 1113 | write, | ||
| 1114 | force, | ||
| 1115 | pages, | ||
| 1116 | vmas); | ||
| 1117 | |||
| 1118 | if (result > 0) | ||
| 1119 | atomic_add(result, | ||
| 1120 | &dev->stats.stat_pages_locked); | ||
| 1121 | |||
| 1122 | return result; | ||
| 1123 | } | ||
| 1124 | |||
| 1125 | void internal_get_page(struct page *page) | ||
| 1126 | { | ||
| 1127 | struct tf_device *dev = tf_get_device(); | ||
| 1128 | |||
| 1129 | atomic_inc(&dev->stats.stat_pages_locked); | ||
| 1130 | |||
| 1131 | get_page(page); | ||
| 1132 | } | ||
| 1133 | |||
| 1134 | void internal_page_cache_release(struct page *page) | ||
| 1135 | { | ||
| 1136 | struct tf_device *dev = tf_get_device(); | ||
| 1137 | |||
| 1138 | atomic_dec(&dev->stats.stat_pages_locked); | ||
| 1139 | |||
| 1140 | page_cache_release(page); | ||
| 1141 | } | ||
| 1142 | |||
| 1143 | |||
diff --git a/security/tf_driver/tf_util.h b/security/tf_driver/tf_util.h new file mode 100644 index 00000000000..14bc78952d8 --- /dev/null +++ b/security/tf_driver/tf_util.h | |||
| @@ -0,0 +1,122 @@ | |||
| 1 | /** | ||
| 2 | * Copyright (c) 2011 Trusted Logic S.A. | ||
| 3 | * All Rights Reserved. | ||
| 4 | * | ||
| 5 | * This program is free software; you can redistribute it and/or | ||
| 6 | * modify it under the terms of the GNU General Public License | ||
| 7 | * version 2 as published by the Free Software Foundation. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, | ||
| 17 | * MA 02111-1307 USA | ||
| 18 | */ | ||
| 19 | |||
| 20 | #ifndef __TF_UTIL_H__ | ||
| 21 | #define __TF_UTIL_H__ | ||
| 22 | |||
| 23 | #include <linux/spinlock.h> | ||
| 24 | #include <linux/errno.h> | ||
| 25 | #include <linux/init.h> | ||
| 26 | #include <linux/module.h> | ||
| 27 | #include <linux/mm.h> | ||
| 28 | #include <linux/crypto.h> | ||
| 29 | #include <linux/mount.h> | ||
| 30 | #include <linux/pagemap.h> | ||
| 31 | #include <linux/vmalloc.h> | ||
| 32 | #include <asm/byteorder.h> | ||
| 33 | |||
| 34 | #include "tf_protocol.h" | ||
| 35 | #include "tf_defs.h" | ||
| 36 | |||
| 37 | /*---------------------------------------------------------------------------- | ||
| 38 | * Debug printing routines | ||
| 39 | *----------------------------------------------------------------------------*/ | ||
| 40 | |||
| 41 | #ifdef CONFIG_TF_DRIVER_DEBUG_SUPPORT | ||
| 42 | extern unsigned tf_debug_level; | ||
| 43 | |||
| 44 | void address_cache_property(unsigned long va); | ||
| 45 | |||
| 46 | #define dprintk(args...) ((void)(tf_debug_level >= 6 ? printk(args) : 0)) | ||
| 47 | #define dpr_info(args...) ((void)(tf_debug_level >= 3 ? pr_info(args) : 0)) | ||
| 48 | #define dpr_err(args...) ((void)(tf_debug_level >= 1 ? pr_err(args) : 0)) | ||
| 49 | #define INFO(fmt, args...) \ | ||
| 50 | (void)dprintk(KERN_INFO "%s: " fmt "\n", __func__, ## args) | ||
| 51 | #define WARNING(fmt, args...) \ | ||
| 52 | (tf_debug_level >= 3 ? \ | ||
| 53 | printk(KERN_WARNING "%s: " fmt "\n", __func__, ## args) : \ | ||
| 54 | (void)0) | ||
| 55 | #define ERROR(fmt, args...) \ | ||
| 56 | (tf_debug_level >= 1 ? \ | ||
| 57 | printk(KERN_ERR "%s: " fmt "\n", __func__, ## args) : \ | ||
| 58 | (void)0) | ||
| 59 | void tf_trace_array(const char *fun, const char *msg, | ||
| 60 | const void *ptr, size_t len); | ||
| 61 | #define TF_TRACE_ARRAY(ptr, len) \ | ||
| 62 | (tf_debug_level >= 7 ? \ | ||
| 63 | tf_trace_array(__func__, #ptr "/" #len, ptr, len) : \ | ||
| 64 | 0) | ||
| 65 | |||
| 66 | void tf_dump_l1_shared_buffer(struct tf_l1_shared_buffer *buffer); | ||
| 67 | |||
| 68 | void tf_dump_command(union tf_command *command); | ||
| 69 | |||
| 70 | void tf_dump_answer(union tf_answer *answer); | ||
| 71 | |||
| 72 | #else /* defined(CONFIG_TF_DRIVER_DEBUG_SUPPORT) */ | ||
| 73 | |||
| 74 | #define dprintk(args...) do { ; } while (0) | ||
| 75 | #define dpr_info(args...) do { ; } while (0) | ||
| 76 | #define dpr_err(args...) do { ; } while (0) | ||
| 77 | #define INFO(fmt, args...) ((void)0) | ||
| 78 | #define WARNING(fmt, args...) ((void)0) | ||
| 79 | #define ERROR(fmt, args...) ((void)0) | ||
| 80 | #define TF_TRACE_ARRAY(ptr, len) ((void)(ptr), (void)(len)) | ||
| 81 | #define tf_dump_l1_shared_buffer(buffer) ((void) 0) | ||
| 82 | #define tf_dump_command(command) ((void) 0) | ||
| 83 | #define tf_dump_answer(answer) ((void) 0) | ||
| 84 | |||
| 85 | #endif /* defined(CONFIG_TF_DRIVER_DEBUG_SUPPORT) */ | ||
| 86 | |||
| 87 | #define SHA1_DIGEST_SIZE 20 | ||
| 88 | |||
| 89 | /*---------------------------------------------------------------------------- | ||
| 90 | * Process identification | ||
| 91 | *----------------------------------------------------------------------------*/ | ||
| 92 | |||
| 93 | int tf_get_current_process_hash(void *hash); | ||
| 94 | |||
| 95 | #ifndef CONFIG_ANDROID | ||
| 96 | int tf_hash_application_path_and_data(char *buffer, void *data, u32 data_len); | ||
| 97 | #endif /* !CONFIG_ANDROID */ | ||
| 98 | |||
| 99 | /*---------------------------------------------------------------------------- | ||
| 100 | * Statistic computation | ||
| 101 | *----------------------------------------------------------------------------*/ | ||
| 102 | |||
| 103 | void *internal_kmalloc(size_t size, int priority); | ||
| 104 | void internal_kfree(void *ptr); | ||
| 105 | void internal_vunmap(void *ptr); | ||
| 106 | void *internal_vmalloc(size_t size); | ||
| 107 | void internal_vfree(void *ptr); | ||
| 108 | unsigned long internal_get_zeroed_page(int priority); | ||
| 109 | void internal_free_page(unsigned long addr); | ||
| 110 | int internal_get_user_pages( | ||
| 111 | struct task_struct *tsk, | ||
| 112 | struct mm_struct *mm, | ||
| 113 | unsigned long start, | ||
| 114 | int len, | ||
| 115 | int write, | ||
| 116 | int force, | ||
| 117 | struct page **pages, | ||
| 118 | struct vm_area_struct **vmas); | ||
| 119 | void internal_get_page(struct page *page); | ||
| 120 | void internal_page_cache_release(struct page *page); | ||
| 121 | #endif /* __TF_UTIL_H__ */ | ||
| 122 | |||
