1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2016, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <kernel/tee_misc.h> 8 #include <kernel/thread.h> 9 #include <mm/core_memprot.h> 10 #include <optee_rpc_cmd.h> 11 #include <stdlib.h> 12 #include <tee/fs_dirfile.h> 13 #include <tee/tee_fs.h> 14 #include <tee/tee_fs_rpc.h> 15 #include <trace.h> 16 #include <util.h> 17 18 struct tee_fs_dir { 19 int nw_dir; 20 struct tee_fs_dirent d; 21 }; 22 23 /* "/dirf.db" or "/<file number>" */ 24 static TEE_Result create_filename(void *buf, size_t blen, 25 const struct tee_fs_dirfile_fileh *dfh) 26 { 27 char *file = buf; 28 size_t pos = 0; 29 size_t l; 30 31 if (pos >= blen) 32 return TEE_ERROR_SHORT_BUFFER; 33 34 file[pos] = '/'; 35 pos++; 36 if (pos >= blen) 37 return TEE_ERROR_SHORT_BUFFER; 38 39 l = blen - pos; 40 return tee_fs_dirfile_fileh_to_fname(dfh, file + pos, &l); 41 } 42 43 static TEE_Result operation_commit(struct tee_fs_rpc_operation *op) 44 { 45 return thread_rpc_cmd(op->id, op->num_params, op->params); 46 } 47 48 static TEE_Result operation_open_dfh(uint32_t id, unsigned int cmd, 49 const struct tee_fs_dirfile_fileh *dfh, 50 int *fd) 51 { 52 struct tee_fs_rpc_operation op = { }; 53 struct mobj *mobj = NULL; 54 TEE_Result res = TEE_SUCCESS; 55 void *va = NULL; 56 57 va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS, 58 THREAD_SHM_TYPE_APPLICATION, 59 TEE_FS_NAME_MAX, &mobj); 60 if (!va) 61 return TEE_ERROR_OUT_OF_MEMORY; 62 63 res = create_filename(va, TEE_FS_NAME_MAX, dfh); 64 if (res != TEE_SUCCESS) 65 return res; 66 67 op = (struct tee_fs_rpc_operation){ 68 .id = id, .num_params = 3, .params = { 69 [0] = THREAD_PARAM_VALUE(IN, cmd, 0, 0), 70 [1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX), 71 [2] = THREAD_PARAM_VALUE(OUT, 0, 0, 0), 72 } }; 73 74 res = operation_commit(&op); 75 if (res == TEE_SUCCESS) 76 *fd = op.params[2].u.value.a; 77 78 return res; 79 } 80 81 82 83 TEE_Result tee_fs_rpc_open_dfh(uint32_t id, 84 const struct tee_fs_dirfile_fileh *dfh, int *fd) 85 { 86 return operation_open_dfh(id, OPTEE_RPC_FS_OPEN, dfh, fd); 87 } 88 89 TEE_Result tee_fs_rpc_create_dfh(uint32_t id, 90 const struct tee_fs_dirfile_fileh *dfh, 91 int *fd) 92 { 93 return operation_open_dfh(id, OPTEE_RPC_FS_CREATE, dfh, fd); 94 } 95 96 TEE_Result tee_fs_rpc_close(uint32_t id, int fd) 97 { 98 struct tee_fs_rpc_operation op = { 99 .id = id, .num_params = 1, .params = { 100 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_CLOSE, fd, 0), 101 }, 102 }; 103 104 return operation_commit(&op); 105 } 106 107 TEE_Result tee_fs_rpc_read_init(struct tee_fs_rpc_operation *op, 108 uint32_t id, int fd, tee_fs_off_t offset, 109 size_t data_len, void **out_data) 110 { 111 struct mobj *mobj; 112 uint8_t *va; 113 114 if (offset < 0) 115 return TEE_ERROR_BAD_PARAMETERS; 116 117 va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS, 118 THREAD_SHM_TYPE_APPLICATION, 119 data_len, &mobj); 120 if (!va) 121 return TEE_ERROR_OUT_OF_MEMORY; 122 123 *op = (struct tee_fs_rpc_operation){ 124 .id = id, .num_params = 2, .params = { 125 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_READ, fd, 126 offset), 127 [1] = THREAD_PARAM_MEMREF(OUT, mobj, 0, data_len), 128 }, 129 }; 130 131 *out_data = va; 132 133 return TEE_SUCCESS; 134 } 135 136 TEE_Result tee_fs_rpc_read_final(struct tee_fs_rpc_operation *op, 137 size_t *data_len) 138 { 139 TEE_Result res = operation_commit(op); 140 141 if (res == TEE_SUCCESS) 142 *data_len = op->params[1].u.memref.size; 143 return res; 144 } 145 146 TEE_Result tee_fs_rpc_write_init(struct tee_fs_rpc_operation *op, 147 uint32_t id, int fd, tee_fs_off_t offset, 148 size_t data_len, void **data) 149 { 150 struct mobj *mobj; 151 uint8_t *va; 152 153 if (offset < 0) 154 return TEE_ERROR_BAD_PARAMETERS; 155 156 va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS, 157 THREAD_SHM_TYPE_APPLICATION, 158 data_len, &mobj); 159 if (!va) 160 return TEE_ERROR_OUT_OF_MEMORY; 161 162 *op = (struct tee_fs_rpc_operation){ 163 .id = id, .num_params = 2, .params = { 164 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_WRITE, fd, 165 offset), 166 [1] = THREAD_PARAM_MEMREF(IN, mobj, 0, data_len), 167 }, 168 }; 169 170 *data = va; 171 172 return TEE_SUCCESS; 173 } 174 175 TEE_Result tee_fs_rpc_write_final(struct tee_fs_rpc_operation *op) 176 { 177 return operation_commit(op); 178 } 179 180 TEE_Result tee_fs_rpc_truncate(uint32_t id, int fd, size_t len) 181 { 182 struct tee_fs_rpc_operation op = { 183 .id = id, .num_params = 1, .params = { 184 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_TRUNCATE, fd, 185 len), 186 } 187 }; 188 189 return operation_commit(&op); 190 } 191 192 TEE_Result tee_fs_rpc_remove_dfh(uint32_t id, 193 const struct tee_fs_dirfile_fileh *dfh) 194 { 195 struct tee_fs_rpc_operation op = { }; 196 TEE_Result res = TEE_SUCCESS; 197 struct mobj *mobj = NULL; 198 void *va = NULL; 199 200 va = thread_rpc_shm_cache_alloc(THREAD_SHM_CACHE_USER_FS, 201 THREAD_SHM_TYPE_APPLICATION, 202 TEE_FS_NAME_MAX, &mobj); 203 if (!va) 204 return TEE_ERROR_OUT_OF_MEMORY; 205 206 207 res = create_filename(va, TEE_FS_NAME_MAX, dfh); 208 if (res != TEE_SUCCESS) 209 return res; 210 211 op = (struct tee_fs_rpc_operation){ 212 .id = id, .num_params = 2, .params = { 213 [0] = THREAD_PARAM_VALUE(IN, OPTEE_RPC_FS_REMOVE, 0, 0), 214 [1] = THREAD_PARAM_MEMREF(IN, mobj, 0, TEE_FS_NAME_MAX), 215 } 216 }; 217 218 return operation_commit(&op); 219 } 220