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