1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Copyright (c) 2016-2017, 2022 Linaro Limited 4 */ 5 6 #ifndef __MM_MOBJ_H 7 #define __MM_MOBJ_H 8 9 #include <compiler.h> 10 #include <mm/core_memprot.h> 11 #include <mm/file.h> 12 #include <mm/fobj.h> 13 #include <string_ext.h> 14 #include <sys/queue.h> 15 #include <tee_api_types.h> 16 #include <types_ext.h> 17 18 #include <optee_msg.h> 19 20 struct mobj { 21 const struct mobj_ops *ops; 22 size_t size; 23 size_t phys_granule; 24 struct refcount refc; 25 }; 26 27 struct mobj_ops { 28 void *(*get_va)(struct mobj *mobj, size_t offs, size_t len); 29 TEE_Result (*get_pa)(struct mobj *mobj, size_t offs, size_t granule, 30 paddr_t *pa); 31 size_t (*get_phys_offs)(struct mobj *mobj, size_t granule); 32 TEE_Result (*get_mem_type)(struct mobj *mobj, uint32_t *mt); 33 bool (*matches)(struct mobj *mobj, enum buf_is_attr attr); 34 void (*free)(struct mobj *mobj); 35 uint64_t (*get_cookie)(struct mobj *mobj); 36 struct fobj *(*get_fobj)(struct mobj *mobj); 37 TEE_Result (*inc_map)(struct mobj *mobj); 38 TEE_Result (*dec_map)(struct mobj *mobj); 39 }; 40 41 extern struct mobj mobj_virt; 42 extern struct mobj *mobj_sec_ddr; 43 extern struct mobj *mobj_tee_ram_rx; 44 extern struct mobj *mobj_tee_ram_rw; 45 46 /* 47 * mobj_get_va() - get virtual address of a mapped mobj 48 * @mobj: memory object 49 * @offset: find the va of this offset into @mobj 50 * @len: how many bytes after @offset that must be valid, can be 1 if 51 * the caller knows by other means that the expected buffer is 52 * available. 53 * 54 * return a virtual address on success or NULL on error 55 */ 56 static inline void *mobj_get_va(struct mobj *mobj, size_t offset, size_t len) 57 { 58 if (mobj && mobj->ops && mobj->ops->get_va) 59 return mobj->ops->get_va(mobj, offset, len); 60 return NULL; 61 } 62 63 static inline TEE_Result mobj_get_pa(struct mobj *mobj, size_t offs, 64 size_t granule, paddr_t *pa) 65 { 66 if (mobj && mobj->ops && mobj->ops->get_pa) 67 return mobj->ops->get_pa(mobj, offs, granule, pa); 68 return TEE_ERROR_GENERIC; 69 } 70 71 static inline size_t mobj_get_phys_offs(struct mobj *mobj, size_t granule) 72 { 73 if (mobj && mobj->ops && mobj->ops->get_phys_offs) 74 return mobj->ops->get_phys_offs(mobj, granule); 75 return 0; 76 } 77 78 static inline TEE_Result mobj_get_mem_type(struct mobj *mobj, uint32_t *mt) 79 { 80 if (mobj && mobj->ops && mobj->ops->get_mem_type) 81 return mobj->ops->get_mem_type(mobj, mt); 82 return TEE_ERROR_GENERIC; 83 } 84 85 static inline bool mobj_matches(struct mobj *mobj, enum buf_is_attr attr) 86 { 87 if (mobj && mobj->ops && mobj->ops->matches) 88 return mobj->ops->matches(mobj, attr); 89 return false; 90 } 91 92 /** 93 * mobj_inc_map() - increase map count 94 * @mobj: pointer to a MOBJ 95 * 96 * Maps the MOBJ if it isn't mapped already and increases the map count 97 * Each call to mobj_inc_map() is supposed to be matches by a call to 98 * mobj_dec_map(). 99 * 100 * Returns TEE_SUCCESS on success or an error code on failure 101 */ 102 static inline TEE_Result mobj_inc_map(struct mobj *mobj) 103 { 104 if (mobj && mobj->ops) { 105 if (mobj->ops->inc_map) 106 return mobj->ops->inc_map(mobj); 107 return TEE_SUCCESS; 108 } 109 return TEE_ERROR_GENERIC; 110 } 111 112 /** 113 * mobj_dec_map() - decrease map count 114 * @mobj: pointer to a MOBJ 115 * 116 * Decreases the map count and also unmaps the MOBJ if the map count 117 * reaches 0. Each call to mobj_inc_map() is supposed to be matched by a 118 * call to mobj_dec_map(). 119 * 120 * Returns TEE_SUCCESS on success or an error code on failure 121 */ 122 static inline TEE_Result mobj_dec_map(struct mobj *mobj) 123 { 124 if (mobj && mobj->ops) { 125 if (mobj->ops->dec_map) 126 return mobj->ops->dec_map(mobj); 127 return TEE_SUCCESS; 128 } 129 return TEE_ERROR_GENERIC; 130 } 131 132 /** 133 * mobj_get() - get a MOBJ 134 * @mobj: Pointer to a MOBJ or NULL 135 * 136 * Increases reference counter of the @mobj 137 * 138 * Returns @mobj with reference counter increased or NULL if @mobj was NULL 139 */ 140 static inline struct mobj *mobj_get(struct mobj *mobj) 141 { 142 if (mobj && !refcount_inc(&mobj->refc)) 143 panic(); 144 145 return mobj; 146 } 147 148 /** 149 * mobj_put() - put a MOBJ 150 * @mobj: Pointer to a MOBJ or NULL 151 * 152 * Decreases reference counter of the @mobj and frees it if the counter 153 * reaches 0. 154 */ 155 static inline void mobj_put(struct mobj *mobj) 156 { 157 if (mobj && refcount_dec(&mobj->refc)) 158 mobj->ops->free(mobj); 159 } 160 161 /** 162 * mobj_put_wipe() - wipe and put a MOBJ 163 * @mobj: Pointer to a MOBJ or NULL 164 * 165 * Clears the memory represented by the mobj and then puts it. 166 */ 167 static inline void mobj_put_wipe(struct mobj *mobj) 168 { 169 if (mobj) { 170 void *buf = mobj_get_va(mobj, 0, mobj->size); 171 172 if (buf) 173 memzero_explicit(buf, mobj->size); 174 mobj_put(mobj); 175 } 176 } 177 178 static inline uint64_t mobj_get_cookie(struct mobj *mobj) 179 { 180 if (mobj && mobj->ops && mobj->ops->get_cookie) 181 return mobj->ops->get_cookie(mobj); 182 183 #if defined(CFG_CORE_FFA) 184 return OPTEE_MSG_FMEM_INVALID_GLOBAL_ID; 185 #else 186 return 0; 187 #endif 188 } 189 190 static inline struct fobj *mobj_get_fobj(struct mobj *mobj) 191 { 192 if (mobj && mobj->ops && mobj->ops->get_fobj) 193 return mobj->ops->get_fobj(mobj); 194 195 return NULL; 196 } 197 198 static inline bool mobj_is_nonsec(struct mobj *mobj) 199 { 200 return mobj_matches(mobj, CORE_MEM_NON_SEC); 201 } 202 203 static inline bool mobj_is_secure(struct mobj *mobj) 204 { 205 return mobj_matches(mobj, CORE_MEM_SEC); 206 } 207 208 static inline bool mobj_is_sdp_mem(struct mobj *mobj) 209 { 210 return mobj_matches(mobj, CORE_MEM_SDP_MEM); 211 } 212 213 static inline size_t mobj_get_phys_granule(struct mobj *mobj) 214 { 215 if (mobj->phys_granule) 216 return mobj->phys_granule; 217 return mobj->size; 218 } 219 220 static inline bool mobj_check_offset_and_len(struct mobj *mobj, size_t offset, 221 size_t len) 222 { 223 size_t end_offs = 0; 224 225 return len && !ADD_OVERFLOW(offset, len - 1, &end_offs) && 226 end_offs < mobj->size; 227 } 228 229 struct mobj *mobj_mm_alloc(struct mobj *mobj_parent, size_t size, 230 tee_mm_pool_t *pool); 231 232 struct mobj *mobj_phys_alloc(paddr_t pa, size_t size, uint32_t cattr, 233 enum buf_is_attr battr); 234 235 #if defined(CFG_CORE_FFA) 236 struct mobj *mobj_ffa_get_by_cookie(uint64_t cookie, 237 unsigned int internal_offs); 238 239 TEE_Result mobj_ffa_unregister_by_cookie(uint64_t cookie); 240 241 /* Functions for SPMC */ 242 #ifdef CFG_CORE_SEL1_SPMC 243 struct mobj_ffa *mobj_ffa_sel1_spmc_new(uint64_t cookie, 244 unsigned int num_pages); 245 void mobj_ffa_sel1_spmc_delete(struct mobj_ffa *mobj); 246 TEE_Result mobj_ffa_sel1_spmc_reclaim(uint64_t cookie); 247 #else 248 struct mobj_ffa *mobj_ffa_spmc_new(uint64_t cookie, unsigned int num_pages); 249 void mobj_ffa_spmc_delete(struct mobj_ffa *mobj); 250 #endif 251 252 uint64_t mobj_ffa_get_cookie(struct mobj_ffa *mobj); 253 TEE_Result mobj_ffa_add_pages_at(struct mobj_ffa *mobj, unsigned int *idx, 254 paddr_t pa, unsigned int num_pages); 255 uint64_t mobj_ffa_push_to_inactive(struct mobj_ffa *mobj); 256 257 #elif defined(CFG_CORE_DYN_SHM) 258 /* reg_shm represents TEE shared memory */ 259 struct mobj *mobj_reg_shm_alloc(paddr_t *pages, size_t num_pages, 260 paddr_t page_offset, uint64_t cookie); 261 262 /** 263 * mobj_reg_shm_get_by_cookie() - get a MOBJ based on cookie 264 * @cookie: Cookie used by normal world when suppling the shared memory 265 * 266 * Searches for a registered shared memory MOBJ and if one with a matching 267 * @cookie is found its reference counter is increased before returning 268 * the MOBJ. 269 * 270 * Returns a valid pointer on success or NULL on failure. 271 */ 272 struct mobj *mobj_reg_shm_get_by_cookie(uint64_t cookie); 273 274 TEE_Result mobj_reg_shm_release_by_cookie(uint64_t cookie); 275 276 /** 277 * mobj_reg_shm_unguard() - unguards a reg_shm 278 * @mobj: pointer to a registered shared memory mobj 279 * 280 * A registered shared memory mobj is normally guarded against being 281 * released with mobj_reg_shm_try_release_by_cookie(). After this function 282 * has returned the mobj can be released by a call to 283 * mobj_reg_shm_try_release_by_cookie() if the reference counter allows it. 284 */ 285 void mobj_reg_shm_unguard(struct mobj *mobj); 286 287 /* 288 * mapped_shm represents registered shared buffer 289 * which is mapped into OPTEE va space 290 */ 291 struct mobj *mobj_mapped_shm_alloc(paddr_t *pages, size_t num_pages, 292 paddr_t page_offset, uint64_t cookie); 293 #endif /*CFG_CORE_DYN_SHM*/ 294 295 #if !defined(CFG_CORE_DYN_SHM) 296 static inline struct mobj *mobj_mapped_shm_alloc(paddr_t *pages __unused, 297 size_t num_pages __unused, 298 paddr_t page_offset __unused, 299 uint64_t cookie __unused) 300 { 301 return NULL; 302 } 303 304 static inline struct mobj *mobj_reg_shm_get_by_cookie(uint64_t cookie __unused) 305 { 306 return NULL; 307 } 308 #endif 309 310 struct mobj *mobj_shm_alloc(paddr_t pa, size_t size, uint64_t cookie); 311 312 #ifdef CFG_PAGED_USER_TA 313 bool mobj_is_paged(struct mobj *mobj); 314 #else 315 static inline bool mobj_is_paged(struct mobj *mobj __unused) 316 { 317 return false; 318 } 319 #endif 320 321 struct mobj *mobj_seccpy_shm_alloc(size_t size); 322 323 struct mobj *mobj_with_fobj_alloc(struct fobj *fobj, struct file *file, 324 uint32_t mem_type); 325 326 #endif /*__MM_MOBJ_H*/ 327