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