1 /* SPDX-License-Identifier: BSD-2-Clause */ 2 /* 3 * Copyright (c) 2016-2024 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 enum mobj_use_case { 21 MOBJ_USE_CASE_NS_SHM, 22 MOBJ_USE_CASE_SEC_VIDEO_PLAY, 23 MOBJ_USE_CASE_TRUSED_UI, 24 }; 25 26 struct mobj { 27 const struct mobj_ops *ops; 28 size_t size; 29 size_t phys_granule; 30 struct refcount refc; 31 }; 32 33 struct mobj_ops { 34 void *(*get_va)(struct mobj *mobj, size_t offs, size_t len); 35 TEE_Result (*get_pa)(struct mobj *mobj, size_t offs, size_t granule, 36 paddr_t *pa); 37 size_t (*get_phys_offs)(struct mobj *mobj, size_t granule); 38 TEE_Result (*get_mem_type)(struct mobj *mobj, uint32_t *mt); 39 bool (*matches)(struct mobj *mobj, enum buf_is_attr attr); 40 void (*free)(struct mobj *mobj); 41 uint64_t (*get_cookie)(struct mobj *mobj); 42 struct fobj *(*get_fobj)(struct mobj *mobj); 43 TEE_Result (*inc_map)(struct mobj *mobj); 44 TEE_Result (*dec_map)(struct mobj *mobj); 45 }; 46 47 extern struct mobj mobj_virt; 48 extern struct mobj *mobj_tee_ram_rx; 49 extern struct mobj *mobj_tee_ram_rw; 50 51 /* 52 * mobj_get_va() - get virtual address of a mapped mobj 53 * @mobj: memory object 54 * @offset: find the va of this offset into @mobj 55 * @len: how many bytes after @offset that must be valid, can be 1 if 56 * the caller knows by other means that the expected buffer is 57 * available. 58 * 59 * return a virtual address on success or NULL on error 60 */ 61 static inline void *mobj_get_va(struct mobj *mobj, size_t offset, size_t len) 62 { 63 if (mobj && mobj->ops && mobj->ops->get_va) 64 return mobj->ops->get_va(mobj, offset, len); 65 return NULL; 66 } 67 68 static inline TEE_Result mobj_get_pa(struct mobj *mobj, size_t offs, 69 size_t granule, paddr_t *pa) 70 { 71 if (mobj && mobj->ops && mobj->ops->get_pa) 72 return mobj->ops->get_pa(mobj, offs, granule, pa); 73 return TEE_ERROR_GENERIC; 74 } 75 76 static inline size_t mobj_get_phys_offs(struct mobj *mobj, size_t granule) 77 { 78 if (mobj && mobj->ops && mobj->ops->get_phys_offs) 79 return mobj->ops->get_phys_offs(mobj, granule); 80 return 0; 81 } 82 83 static inline TEE_Result mobj_get_mem_type(struct mobj *mobj, uint32_t *mt) 84 { 85 if (mobj && mobj->ops && mobj->ops->get_mem_type) 86 return mobj->ops->get_mem_type(mobj, mt); 87 return TEE_ERROR_GENERIC; 88 } 89 90 static inline bool mobj_matches(struct mobj *mobj, enum buf_is_attr attr) 91 { 92 if (mobj && mobj->ops && mobj->ops->matches) 93 return mobj->ops->matches(mobj, attr); 94 return false; 95 } 96 97 /** 98 * mobj_inc_map() - increase map count 99 * @mobj: pointer to a MOBJ 100 * 101 * Maps the MOBJ if it isn't mapped already and increases the map count 102 * Each call to mobj_inc_map() is supposed to be matches by a call to 103 * mobj_dec_map(). 104 * 105 * Returns TEE_SUCCESS on success or an error code on failure 106 */ 107 static inline TEE_Result mobj_inc_map(struct mobj *mobj) 108 { 109 if (mobj && mobj->ops) { 110 if (mobj->ops->inc_map) 111 return mobj->ops->inc_map(mobj); 112 return TEE_SUCCESS; 113 } 114 return TEE_ERROR_GENERIC; 115 } 116 117 /** 118 * mobj_dec_map() - decrease map count 119 * @mobj: pointer to a MOBJ 120 * 121 * Decreases the map count and also unmaps the MOBJ if the map count 122 * reaches 0. Each call to mobj_inc_map() is supposed to be matched by a 123 * call to mobj_dec_map(). 124 * 125 * Returns TEE_SUCCESS on success or an error code on failure 126 */ 127 static inline TEE_Result mobj_dec_map(struct mobj *mobj) 128 { 129 if (mobj && mobj->ops) { 130 if (mobj->ops->dec_map) 131 return mobj->ops->dec_map(mobj); 132 return TEE_SUCCESS; 133 } 134 return TEE_ERROR_GENERIC; 135 } 136 137 /** 138 * mobj_get() - get a MOBJ 139 * @mobj: Pointer to a MOBJ or NULL 140 * 141 * Increases reference counter of the @mobj 142 * 143 * Returns @mobj with reference counter increased or NULL if @mobj was NULL 144 */ 145 static inline struct mobj *mobj_get(struct mobj *mobj) 146 { 147 if (mobj && !refcount_inc(&mobj->refc)) 148 panic(); 149 150 return mobj; 151 } 152 153 /** 154 * mobj_put() - put a MOBJ 155 * @mobj: Pointer to a MOBJ or NULL 156 * 157 * Decreases reference counter of the @mobj and frees it if the counter 158 * reaches 0. 159 */ 160 static inline void mobj_put(struct mobj *mobj) 161 { 162 if (mobj && refcount_dec(&mobj->refc)) 163 mobj->ops->free(mobj); 164 } 165 166 /** 167 * mobj_put_wipe() - wipe and put a MOBJ 168 * @mobj: Pointer to a MOBJ or NULL 169 * 170 * Clears the memory represented by the mobj and then puts it. 171 */ 172 static inline void mobj_put_wipe(struct mobj *mobj) 173 { 174 if (mobj) { 175 void *buf = mobj_get_va(mobj, 0, mobj->size); 176 177 if (buf) 178 memzero_explicit(buf, mobj->size); 179 mobj_put(mobj); 180 } 181 } 182 183 static inline uint64_t mobj_get_cookie(struct mobj *mobj) 184 { 185 if (mobj && mobj->ops && mobj->ops->get_cookie) 186 return mobj->ops->get_cookie(mobj); 187 188 #if defined(CFG_CORE_FFA) 189 return OPTEE_MSG_FMEM_INVALID_GLOBAL_ID; 190 #else 191 return 0; 192 #endif 193 } 194 195 static inline struct fobj *mobj_get_fobj(struct mobj *mobj) 196 { 197 if (mobj && mobj->ops && mobj->ops->get_fobj) 198 return mobj->ops->get_fobj(mobj); 199 200 return NULL; 201 } 202 203 static inline bool mobj_is_nonsec(struct mobj *mobj) 204 { 205 return mobj_matches(mobj, CORE_MEM_NON_SEC); 206 } 207 208 static inline bool mobj_is_secure(struct mobj *mobj) 209 { 210 return mobj_matches(mobj, CORE_MEM_SEC); 211 } 212 213 static inline bool mobj_is_sdp_mem(struct mobj *mobj) 214 { 215 return mobj_matches(mobj, CORE_MEM_SDP_MEM); 216 } 217 218 static inline size_t mobj_get_phys_granule(struct mobj *mobj) 219 { 220 if (mobj->phys_granule) 221 return mobj->phys_granule; 222 return mobj->size; 223 } 224 225 static inline bool mobj_check_offset_and_len(struct mobj *mobj, size_t offset, 226 size_t len) 227 { 228 size_t end_offs = 0; 229 230 return len && !ADD_OVERFLOW(offset, len - 1, &end_offs) && 231 end_offs < mobj->size; 232 } 233 234 struct mobj *mobj_phys_alloc(paddr_t pa, size_t size, uint32_t cattr, 235 enum buf_is_attr battr); 236 237 #if defined(CFG_CORE_FFA) 238 struct mobj *mobj_ffa_get_by_cookie(uint64_t cookie, 239 unsigned int internal_offs); 240 241 TEE_Result mobj_ffa_unregister_by_cookie(uint64_t cookie); 242 243 /* Functions for SPMC */ 244 #ifdef CFG_CORE_SEL1_SPMC 245 struct mobj_ffa *mobj_ffa_sel1_spmc_new(uint64_t cookie, 246 unsigned int num_pages, 247 enum mobj_use_case use_case); 248 void mobj_ffa_sel1_spmc_delete(struct mobj_ffa *mobj); 249 TEE_Result mobj_ffa_sel1_spmc_reclaim(uint64_t cookie); 250 #else 251 struct mobj_ffa *mobj_ffa_spmc_new(uint64_t cookie, unsigned int num_pages, 252 enum mobj_use_case use_case); 253 void mobj_ffa_spmc_delete(struct mobj_ffa *mobj); 254 #endif 255 256 uint64_t mobj_ffa_get_cookie(struct mobj_ffa *mobj); 257 TEE_Result mobj_ffa_add_pages_at(struct mobj_ffa *mobj, unsigned int *idx, 258 paddr_t pa, unsigned int num_pages); 259 TEE_Result mobj_ffa_push_to_inactive(struct mobj_ffa *mobj); 260 261 #ifdef CFG_CORE_DYN_PROTMEM 262 TEE_Result mobj_ffa_assign_protmem(uint64_t cookie, 263 enum mobj_use_case use_case); 264 struct mobj *mobj_ffa_protmem_get_by_pa(paddr_t pa, paddr_size_t size); 265 #endif 266 267 #elif defined(CFG_CORE_DYN_SHM) 268 /* reg_shm represents TEE shared memory */ 269 struct mobj *mobj_reg_shm_alloc(paddr_t *pages, size_t num_pages, 270 paddr_t page_offset, uint64_t cookie); 271 272 /** 273 * mobj_reg_shm_get_by_cookie() - get a MOBJ based on cookie 274 * @cookie: Cookie used by normal world when suppling the shared memory 275 * 276 * Searches for a registered shared memory MOBJ and if one with a matching 277 * @cookie is found its reference counter is increased before returning 278 * the MOBJ. 279 * 280 * Returns a valid pointer on success or NULL on failure. 281 */ 282 struct mobj *mobj_reg_shm_get_by_cookie(uint64_t cookie); 283 284 TEE_Result mobj_reg_shm_release_by_cookie(uint64_t cookie); 285 286 /** 287 * mobj_reg_shm_unguard() - unguards a reg_shm 288 * @mobj: pointer to a registered shared memory mobj 289 * 290 * A registered shared memory mobj is normally guarded against being 291 * released with mobj_reg_shm_try_release_by_cookie(). After this function 292 * has returned the mobj can be released by a call to 293 * mobj_reg_shm_try_release_by_cookie() if the reference counter allows it. 294 */ 295 void mobj_reg_shm_unguard(struct mobj *mobj); 296 297 /* 298 * mapped_shm represents registered shared buffer 299 * which is mapped into OPTEE va space 300 */ 301 struct mobj *mobj_mapped_shm_alloc(paddr_t *pages, size_t num_pages, 302 paddr_t page_offset, uint64_t cookie); 303 304 #if defined(CFG_CORE_DYN_PROTMEM) 305 struct mobj *mobj_protmem_alloc(paddr_t pa, paddr_size_t size, uint64_t cookie, 306 enum mobj_use_case use_case); 307 TEE_Result mobj_protmem_release_by_cookie(uint64_t cookie); 308 struct mobj *mobj_protmem_get_by_pa(paddr_t pa, paddr_size_t size); 309 #endif /*CFG_CORE_DYN_PROTMEM*/ 310 311 #endif /*CFG_CORE_DYN_SHM*/ 312 313 #if !defined(CFG_CORE_DYN_SHM) 314 static inline struct mobj *mobj_mapped_shm_alloc(paddr_t *pages __unused, 315 size_t num_pages __unused, 316 paddr_t page_offset __unused, 317 uint64_t cookie __unused) 318 { 319 return NULL; 320 } 321 322 static inline struct mobj *mobj_reg_shm_get_by_cookie(uint64_t cookie __unused) 323 { 324 return NULL; 325 } 326 #endif 327 328 #if !defined(CFG_CORE_DYN_PROTMEM) || defined(CFG_CORE_FFA) 329 static inline struct mobj * 330 mobj_protmem_alloc(paddr_t pa __unused, paddr_size_t size __unused, 331 uint64_t cookie __unused, 332 enum mobj_use_case use_case __unused) 333 { 334 return NULL; 335 } 336 337 static inline TEE_Result 338 mobj_protmem_release_by_cookie(uint64_t cookie __unused) 339 { 340 return TEE_ERROR_NOT_IMPLEMENTED; 341 } 342 343 static inline struct mobj *mobj_protmem_get_by_pa(paddr_t pa __unused, 344 paddr_size_t size __unused) 345 { 346 return NULL; 347 } 348 #endif 349 350 #if !defined(CFG_CORE_DYN_PROTMEM) || !defined(CFG_CORE_FFA) 351 static inline struct mobj * 352 mobj_ffa_protmem_get_by_pa(paddr_t pa __unused, paddr_size_t size __unused) 353 { 354 return NULL; 355 } 356 357 static inline TEE_Result 358 mobj_ffa_assign_protmem(uint64_t cookie __unused, 359 enum mobj_use_case use_case __unused) 360 { 361 return TEE_ERROR_NOT_IMPLEMENTED; 362 } 363 #endif 364 365 #if !defined(CFG_CORE_FFA) 366 static inline struct mobj * 367 mobj_ffa_get_by_cookie(uint64_t cookie __unused, 368 unsigned int internal_offs __unused) 369 { 370 return NULL; 371 } 372 #endif 373 374 struct mobj *mobj_shm_alloc(paddr_t pa, size_t size, uint64_t cookie); 375 376 #ifdef CFG_PAGED_USER_TA 377 bool mobj_is_paged(struct mobj *mobj); 378 #else 379 static inline bool mobj_is_paged(struct mobj *mobj __unused) 380 { 381 return false; 382 } 383 #endif 384 385 struct mobj *mobj_with_fobj_alloc(struct fobj *fobj, struct file *file, 386 uint32_t mem_type); 387 388 #ifdef CFG_CORE_DYN_PROTMEM 389 /* 390 * plat_get_protmem_config() - Platform specific config for a protected memory 391 * use-case 392 * @use_case: Identifies the protected memory use-case 393 * @min_mem_sz: out value for minumim memory size 394 * @min_mem_align: out value for minimum alignment 395 * 396 * The function is not supposed to be called with MOBJ_USE_CASE_NS_SHM as 397 * @use_case, but any other defined enum value is up to the platform. 398 * 399 * returns TEE_Result value 400 */ 401 TEE_Result plat_get_protmem_config(enum mobj_use_case use_case, 402 size_t *min_mem_sz, size_t *min_mem_align); 403 404 /* 405 * plat_set_protmem_range() - Platform specific change of memory protection 406 * @use_case: Identifies the protected memory use-case 407 * @pa: Start physical address 408 * @sz: Size of the memory range 409 * 410 * The @use_case defines how the supplied memory range should be protected. 411 * The function can be called with MOBJ_USE_CASE_NS_SHM as @use_case to 412 * restore the non-protected state. 413 * 414 * returns TEE_Result value 415 */ 416 417 TEE_Result plat_set_protmem_range(enum mobj_use_case use_case, paddr_t pa, 418 paddr_size_t sz); 419 #else 420 static inline TEE_Result 421 plat_get_protmem_config(enum mobj_use_case use_case __unused, 422 size_t *min_mem_sz __unused, 423 size_t *min_mem_align __unused) 424 { 425 return TEE_ERROR_BAD_PARAMETERS; 426 } 427 428 static inline TEE_Result 429 plat_set_protmem_range(enum mobj_use_case use_case __unused, 430 paddr_t pa __unused, paddr_size_t sz __unused) 431 { 432 return TEE_ERROR_BAD_PARAMETERS; 433 } 434 #endif 435 436 #endif /*__MM_MOBJ_H*/ 437