1185b4595SMarouene Boubakri // SPDX-License-Identifier: BSD-2-Clause 2185b4595SMarouene Boubakri /* 3d5ad7ccfSJens Wiklander * Copyright (c) 2016-2021, Linaro Limited 4185b4595SMarouene Boubakri */ 5185b4595SMarouene Boubakri 6185b4595SMarouene Boubakri #include <assert.h> 7185b4595SMarouene Boubakri #include <initcall.h> 8185b4595SMarouene Boubakri #include <keep.h> 9185b4595SMarouene Boubakri #include <kernel/linker.h> 10185b4595SMarouene Boubakri #include <kernel/mutex.h> 11185b4595SMarouene Boubakri #include <kernel/panic.h> 12185b4595SMarouene Boubakri #include <kernel/refcount.h> 13185b4595SMarouene Boubakri #include <kernel/spinlock.h> 14185b4595SMarouene Boubakri #include <kernel/tee_misc.h> 15185b4595SMarouene Boubakri #include <mm/core_mmu.h> 16185b4595SMarouene Boubakri #include <mm/mobj.h> 17185b4595SMarouene Boubakri #include <mm/tee_pager.h> 18185b4595SMarouene Boubakri #include <mm/vm.h> 19185b4595SMarouene Boubakri #include <optee_msg.h> 20185b4595SMarouene Boubakri #include <sm/optee_smc.h> 21185b4595SMarouene Boubakri #include <stdlib.h> 22185b4595SMarouene Boubakri #include <tee_api_types.h> 23185b4595SMarouene Boubakri #include <types_ext.h> 24185b4595SMarouene Boubakri #include <util.h> 25185b4595SMarouene Boubakri 26185b4595SMarouene Boubakri struct mobj *mobj_sec_ddr; 27185b4595SMarouene Boubakri struct mobj *mobj_tee_ram; 28185b4595SMarouene Boubakri 29185b4595SMarouene Boubakri /* 30185b4595SMarouene Boubakri * mobj_phys implementation 31185b4595SMarouene Boubakri */ 32185b4595SMarouene Boubakri 33185b4595SMarouene Boubakri struct mobj_phys { 34185b4595SMarouene Boubakri struct mobj mobj; 35185b4595SMarouene Boubakri enum buf_is_attr battr; 36185b4595SMarouene Boubakri uint32_t cattr; /* Defined by TEE_MATTR_CACHE_* in tee_mmu_types.h */ 37185b4595SMarouene Boubakri vaddr_t va; 38185b4595SMarouene Boubakri paddr_t pa; 39185b4595SMarouene Boubakri }; 40185b4595SMarouene Boubakri 41185b4595SMarouene Boubakri static struct mobj_phys *to_mobj_phys(struct mobj *mobj); 42185b4595SMarouene Boubakri 43185b4595SMarouene Boubakri static void *mobj_phys_get_va(struct mobj *mobj, size_t offset) 44185b4595SMarouene Boubakri { 45185b4595SMarouene Boubakri struct mobj_phys *moph = to_mobj_phys(mobj); 46185b4595SMarouene Boubakri 47185b4595SMarouene Boubakri if (!moph->va || offset >= mobj->size) 48185b4595SMarouene Boubakri return NULL; 49185b4595SMarouene Boubakri 50185b4595SMarouene Boubakri return (void *)(moph->va + offset); 51185b4595SMarouene Boubakri } 52185b4595SMarouene Boubakri 53185b4595SMarouene Boubakri static TEE_Result mobj_phys_get_pa(struct mobj *mobj, size_t offs, 54185b4595SMarouene Boubakri size_t granule, paddr_t *pa) 55185b4595SMarouene Boubakri { 56185b4595SMarouene Boubakri struct mobj_phys *moph = to_mobj_phys(mobj); 57185b4595SMarouene Boubakri paddr_t p; 58185b4595SMarouene Boubakri 59185b4595SMarouene Boubakri if (!pa) 60185b4595SMarouene Boubakri return TEE_ERROR_GENERIC; 61185b4595SMarouene Boubakri 62185b4595SMarouene Boubakri p = moph->pa + offs; 63185b4595SMarouene Boubakri 64185b4595SMarouene Boubakri if (granule) { 65185b4595SMarouene Boubakri if (granule != SMALL_PAGE_SIZE && 66185b4595SMarouene Boubakri granule != CORE_MMU_PGDIR_SIZE) 67185b4595SMarouene Boubakri return TEE_ERROR_GENERIC; 68185b4595SMarouene Boubakri p &= ~(granule - 1); 69185b4595SMarouene Boubakri } 70185b4595SMarouene Boubakri 71185b4595SMarouene Boubakri *pa = p; 72185b4595SMarouene Boubakri return TEE_SUCCESS; 73185b4595SMarouene Boubakri } 74185b4595SMarouene Boubakri DECLARE_KEEP_PAGER(mobj_phys_get_pa); 75185b4595SMarouene Boubakri 76185b4595SMarouene Boubakri static TEE_Result mobj_phys_get_cattr(struct mobj *mobj, uint32_t *cattr) 77185b4595SMarouene Boubakri { 78185b4595SMarouene Boubakri struct mobj_phys *moph = to_mobj_phys(mobj); 79185b4595SMarouene Boubakri 80185b4595SMarouene Boubakri if (!cattr) 81185b4595SMarouene Boubakri return TEE_ERROR_GENERIC; 82185b4595SMarouene Boubakri 83185b4595SMarouene Boubakri *cattr = moph->cattr; 84185b4595SMarouene Boubakri return TEE_SUCCESS; 85185b4595SMarouene Boubakri } 86185b4595SMarouene Boubakri 87185b4595SMarouene Boubakri static bool mobj_phys_matches(struct mobj *mobj, enum buf_is_attr attr) 88185b4595SMarouene Boubakri { 89185b4595SMarouene Boubakri struct mobj_phys *moph = to_mobj_phys(mobj); 90185b4595SMarouene Boubakri enum buf_is_attr a; 91185b4595SMarouene Boubakri 92185b4595SMarouene Boubakri a = moph->battr; 93185b4595SMarouene Boubakri 94185b4595SMarouene Boubakri switch (attr) { 95185b4595SMarouene Boubakri case CORE_MEM_SEC: 96185b4595SMarouene Boubakri return a == CORE_MEM_SEC || a == CORE_MEM_TEE_RAM || 97185b4595SMarouene Boubakri a == CORE_MEM_TA_RAM || a == CORE_MEM_SDP_MEM; 98185b4595SMarouene Boubakri case CORE_MEM_NON_SEC: 99185b4595SMarouene Boubakri return a == CORE_MEM_NSEC_SHM; 100185b4595SMarouene Boubakri case CORE_MEM_TEE_RAM: 101185b4595SMarouene Boubakri case CORE_MEM_TA_RAM: 102185b4595SMarouene Boubakri case CORE_MEM_NSEC_SHM: 103185b4595SMarouene Boubakri case CORE_MEM_SDP_MEM: 104185b4595SMarouene Boubakri return attr == a; 105185b4595SMarouene Boubakri default: 106185b4595SMarouene Boubakri return false; 107185b4595SMarouene Boubakri } 108185b4595SMarouene Boubakri } 109185b4595SMarouene Boubakri 110185b4595SMarouene Boubakri static void mobj_phys_free(struct mobj *mobj) 111185b4595SMarouene Boubakri { 112185b4595SMarouene Boubakri struct mobj_phys *moph = to_mobj_phys(mobj); 113185b4595SMarouene Boubakri 114185b4595SMarouene Boubakri free(moph); 115185b4595SMarouene Boubakri } 116185b4595SMarouene Boubakri 117*00361c18SJens Wiklander /* 118*00361c18SJens Wiklander * Note: this variable is weak just to ease breaking its dependency chain 119*00361c18SJens Wiklander * when added to the unpaged area. 120*00361c18SJens Wiklander */ 121*00361c18SJens Wiklander const struct mobj_ops mobj_phys_ops __weak __rodata_unpaged("mobj_phys_ops") = { 122185b4595SMarouene Boubakri .get_va = mobj_phys_get_va, 123185b4595SMarouene Boubakri .get_pa = mobj_phys_get_pa, 124185b4595SMarouene Boubakri .get_phys_offs = NULL, /* only offset 0 */ 125185b4595SMarouene Boubakri .get_cattr = mobj_phys_get_cattr, 126185b4595SMarouene Boubakri .matches = mobj_phys_matches, 127185b4595SMarouene Boubakri .free = mobj_phys_free, 128185b4595SMarouene Boubakri }; 129185b4595SMarouene Boubakri 130185b4595SMarouene Boubakri static struct mobj_phys *to_mobj_phys(struct mobj *mobj) 131185b4595SMarouene Boubakri { 132185b4595SMarouene Boubakri assert(mobj->ops == &mobj_phys_ops); 133185b4595SMarouene Boubakri return container_of(mobj, struct mobj_phys, mobj); 134185b4595SMarouene Boubakri } 135185b4595SMarouene Boubakri 136185b4595SMarouene Boubakri struct mobj *mobj_phys_alloc(paddr_t pa, size_t size, uint32_t cattr, 137185b4595SMarouene Boubakri enum buf_is_attr battr) 138185b4595SMarouene Boubakri { 139185b4595SMarouene Boubakri struct mobj_phys *moph; 140185b4595SMarouene Boubakri enum teecore_memtypes area_type; 141185b4595SMarouene Boubakri void *va; 142185b4595SMarouene Boubakri 143185b4595SMarouene Boubakri if ((pa & CORE_MMU_USER_PARAM_MASK) || 144185b4595SMarouene Boubakri (size & CORE_MMU_USER_PARAM_MASK)) { 145185b4595SMarouene Boubakri DMSG("Expect %#x alignment", CORE_MMU_USER_PARAM_SIZE); 146185b4595SMarouene Boubakri return NULL; 147185b4595SMarouene Boubakri } 148185b4595SMarouene Boubakri 149185b4595SMarouene Boubakri switch (battr) { 150185b4595SMarouene Boubakri case CORE_MEM_TEE_RAM: 151185b4595SMarouene Boubakri area_type = MEM_AREA_TEE_RAM_RW_DATA; 152185b4595SMarouene Boubakri break; 153185b4595SMarouene Boubakri case CORE_MEM_TA_RAM: 154185b4595SMarouene Boubakri area_type = MEM_AREA_TA_RAM; 155185b4595SMarouene Boubakri break; 156185b4595SMarouene Boubakri case CORE_MEM_NSEC_SHM: 157185b4595SMarouene Boubakri area_type = MEM_AREA_NSEC_SHM; 158185b4595SMarouene Boubakri break; 159185b4595SMarouene Boubakri case CORE_MEM_SDP_MEM: 160185b4595SMarouene Boubakri area_type = MEM_AREA_SDP_MEM; 161185b4595SMarouene Boubakri break; 162185b4595SMarouene Boubakri default: 163185b4595SMarouene Boubakri DMSG("can't allocate with specified attribute"); 164185b4595SMarouene Boubakri return NULL; 165185b4595SMarouene Boubakri } 166185b4595SMarouene Boubakri 167185b4595SMarouene Boubakri /* Only SDP memory may not have a virtual address */ 168185b4595SMarouene Boubakri va = phys_to_virt(pa, area_type); 169185b4595SMarouene Boubakri if (!va && battr != CORE_MEM_SDP_MEM) 170185b4595SMarouene Boubakri return NULL; 171185b4595SMarouene Boubakri 172185b4595SMarouene Boubakri moph = calloc(1, sizeof(*moph)); 173185b4595SMarouene Boubakri if (!moph) 174185b4595SMarouene Boubakri return NULL; 175185b4595SMarouene Boubakri 176185b4595SMarouene Boubakri moph->battr = battr; 177185b4595SMarouene Boubakri moph->cattr = cattr; 178185b4595SMarouene Boubakri moph->mobj.size = size; 179185b4595SMarouene Boubakri moph->mobj.ops = &mobj_phys_ops; 180185b4595SMarouene Boubakri refcount_set(&moph->mobj.refc, 1); 181185b4595SMarouene Boubakri moph->pa = pa; 182185b4595SMarouene Boubakri moph->va = (vaddr_t)va; 183185b4595SMarouene Boubakri 184185b4595SMarouene Boubakri return &moph->mobj; 185185b4595SMarouene Boubakri } 186185b4595SMarouene Boubakri 187185b4595SMarouene Boubakri /* 188185b4595SMarouene Boubakri * mobj_virt implementation 189185b4595SMarouene Boubakri */ 190185b4595SMarouene Boubakri 191185b4595SMarouene Boubakri static void mobj_virt_assert_type(struct mobj *mobj); 192185b4595SMarouene Boubakri 193185b4595SMarouene Boubakri static void *mobj_virt_get_va(struct mobj *mobj, size_t offset) 194185b4595SMarouene Boubakri { 195185b4595SMarouene Boubakri mobj_virt_assert_type(mobj); 196185b4595SMarouene Boubakri 197185b4595SMarouene Boubakri return (void *)(vaddr_t)offset; 198185b4595SMarouene Boubakri } 199185b4595SMarouene Boubakri 200*00361c18SJens Wiklander /* 201*00361c18SJens Wiklander * Note: this variable is weak just to ease breaking its dependency chain 202*00361c18SJens Wiklander * when added to the unpaged area. 203*00361c18SJens Wiklander */ 204*00361c18SJens Wiklander const struct mobj_ops mobj_virt_ops __weak __rodata_unpaged("mobj_virt_ops") = { 205185b4595SMarouene Boubakri .get_va = mobj_virt_get_va, 206185b4595SMarouene Boubakri }; 207185b4595SMarouene Boubakri 208185b4595SMarouene Boubakri static void mobj_virt_assert_type(struct mobj *mobj __maybe_unused) 209185b4595SMarouene Boubakri { 210185b4595SMarouene Boubakri assert(mobj->ops == &mobj_virt_ops); 211185b4595SMarouene Boubakri } 212185b4595SMarouene Boubakri 213185b4595SMarouene Boubakri struct mobj mobj_virt = { .ops = &mobj_virt_ops, .size = SIZE_MAX }; 214185b4595SMarouene Boubakri 215185b4595SMarouene Boubakri /* 216185b4595SMarouene Boubakri * mobj_mm implementation 217185b4595SMarouene Boubakri */ 218185b4595SMarouene Boubakri 219185b4595SMarouene Boubakri struct mobj_mm { 220185b4595SMarouene Boubakri tee_mm_entry_t *mm; 221185b4595SMarouene Boubakri struct mobj *parent_mobj; 222185b4595SMarouene Boubakri struct mobj mobj; 223185b4595SMarouene Boubakri }; 224185b4595SMarouene Boubakri 225185b4595SMarouene Boubakri static struct mobj_mm *to_mobj_mm(struct mobj *mobj); 226185b4595SMarouene Boubakri 227185b4595SMarouene Boubakri static size_t mobj_mm_offs(struct mobj *mobj, size_t offs) 228185b4595SMarouene Boubakri { 229185b4595SMarouene Boubakri tee_mm_entry_t *mm = to_mobj_mm(mobj)->mm; 230185b4595SMarouene Boubakri 231185b4595SMarouene Boubakri return (mm->offset << mm->pool->shift) + offs; 232185b4595SMarouene Boubakri } 233185b4595SMarouene Boubakri 234185b4595SMarouene Boubakri static void *mobj_mm_get_va(struct mobj *mobj, size_t offs) 235185b4595SMarouene Boubakri { 236185b4595SMarouene Boubakri return mobj_get_va(to_mobj_mm(mobj)->parent_mobj, 237185b4595SMarouene Boubakri mobj_mm_offs(mobj, offs)); 238185b4595SMarouene Boubakri } 239185b4595SMarouene Boubakri 240185b4595SMarouene Boubakri 241185b4595SMarouene Boubakri static TEE_Result mobj_mm_get_pa(struct mobj *mobj, size_t offs, 242185b4595SMarouene Boubakri size_t granule, paddr_t *pa) 243185b4595SMarouene Boubakri { 244185b4595SMarouene Boubakri return mobj_get_pa(to_mobj_mm(mobj)->parent_mobj, 245185b4595SMarouene Boubakri mobj_mm_offs(mobj, offs), granule, pa); 246185b4595SMarouene Boubakri } 247185b4595SMarouene Boubakri DECLARE_KEEP_PAGER(mobj_mm_get_pa); 248185b4595SMarouene Boubakri 249185b4595SMarouene Boubakri static size_t mobj_mm_get_phys_offs(struct mobj *mobj, size_t granule) 250185b4595SMarouene Boubakri { 251185b4595SMarouene Boubakri return mobj_get_phys_offs(to_mobj_mm(mobj)->parent_mobj, granule); 252185b4595SMarouene Boubakri } 253185b4595SMarouene Boubakri 254185b4595SMarouene Boubakri static TEE_Result mobj_mm_get_cattr(struct mobj *mobj, uint32_t *cattr) 255185b4595SMarouene Boubakri { 256185b4595SMarouene Boubakri return mobj_get_cattr(to_mobj_mm(mobj)->parent_mobj, cattr); 257185b4595SMarouene Boubakri } 258185b4595SMarouene Boubakri 259185b4595SMarouene Boubakri static bool mobj_mm_matches(struct mobj *mobj, enum buf_is_attr attr) 260185b4595SMarouene Boubakri { 261185b4595SMarouene Boubakri return mobj_matches(to_mobj_mm(mobj)->parent_mobj, attr); 262185b4595SMarouene Boubakri } 263185b4595SMarouene Boubakri 264185b4595SMarouene Boubakri static void mobj_mm_free(struct mobj *mobj) 265185b4595SMarouene Boubakri { 266185b4595SMarouene Boubakri struct mobj_mm *m = to_mobj_mm(mobj); 267185b4595SMarouene Boubakri 268185b4595SMarouene Boubakri tee_mm_free(m->mm); 269185b4595SMarouene Boubakri free(m); 270185b4595SMarouene Boubakri } 271185b4595SMarouene Boubakri 272*00361c18SJens Wiklander /* 273*00361c18SJens Wiklander * Note: this variable is weak just to ease breaking its dependency chain 274*00361c18SJens Wiklander * when added to the unpaged area. 275*00361c18SJens Wiklander */ 276*00361c18SJens Wiklander const struct mobj_ops mobj_mm_ops __weak __rodata_unpaged("mobj_mm_ops") = { 277185b4595SMarouene Boubakri .get_va = mobj_mm_get_va, 278185b4595SMarouene Boubakri .get_pa = mobj_mm_get_pa, 279185b4595SMarouene Boubakri .get_phys_offs = mobj_mm_get_phys_offs, 280185b4595SMarouene Boubakri .get_cattr = mobj_mm_get_cattr, 281185b4595SMarouene Boubakri .matches = mobj_mm_matches, 282185b4595SMarouene Boubakri .free = mobj_mm_free, 283185b4595SMarouene Boubakri }; 284185b4595SMarouene Boubakri 285185b4595SMarouene Boubakri static struct mobj_mm *to_mobj_mm(struct mobj *mobj) 286185b4595SMarouene Boubakri { 287185b4595SMarouene Boubakri assert(mobj->ops == &mobj_mm_ops); 288185b4595SMarouene Boubakri return container_of(mobj, struct mobj_mm, mobj); 289185b4595SMarouene Boubakri } 290185b4595SMarouene Boubakri 291185b4595SMarouene Boubakri struct mobj *mobj_mm_alloc(struct mobj *mobj_parent, size_t size, 292185b4595SMarouene Boubakri tee_mm_pool_t *pool) 293185b4595SMarouene Boubakri { 294185b4595SMarouene Boubakri struct mobj_mm *m = calloc(1, sizeof(*m)); 295185b4595SMarouene Boubakri 296185b4595SMarouene Boubakri if (!m) 297185b4595SMarouene Boubakri return NULL; 298185b4595SMarouene Boubakri 299185b4595SMarouene Boubakri m->mm = tee_mm_alloc(pool, size); 300185b4595SMarouene Boubakri if (!m->mm) { 301185b4595SMarouene Boubakri free(m); 302185b4595SMarouene Boubakri return NULL; 303185b4595SMarouene Boubakri } 304185b4595SMarouene Boubakri 305185b4595SMarouene Boubakri m->parent_mobj = mobj_parent; 306185b4595SMarouene Boubakri m->mobj.size = size; 307185b4595SMarouene Boubakri m->mobj.ops = &mobj_mm_ops; 308185b4595SMarouene Boubakri refcount_set(&m->mobj.refc, 1); 309185b4595SMarouene Boubakri 310185b4595SMarouene Boubakri return &m->mobj; 311185b4595SMarouene Boubakri } 312185b4595SMarouene Boubakri 313185b4595SMarouene Boubakri 314185b4595SMarouene Boubakri /* 315185b4595SMarouene Boubakri * mobj_shm implementation. mobj_shm represents buffer in predefined shm region 316185b4595SMarouene Boubakri * - it is physically contiguous. 317185b4595SMarouene Boubakri * - it is identified in static physical layout as MEM_AREA_NSEC_SHM. 318185b4595SMarouene Boubakri * - it creates mobjs that match specific CORE_MEM_NSEC_SHM and non secure 319185b4595SMarouene Boubakri * generic CORE_MEM_NON_SEC. 320185b4595SMarouene Boubakri */ 321185b4595SMarouene Boubakri 322185b4595SMarouene Boubakri struct mobj_shm { 323185b4595SMarouene Boubakri struct mobj mobj; 324185b4595SMarouene Boubakri paddr_t pa; 325185b4595SMarouene Boubakri uint64_t cookie; 326185b4595SMarouene Boubakri }; 327185b4595SMarouene Boubakri 328185b4595SMarouene Boubakri static struct mobj_shm *to_mobj_shm(struct mobj *mobj); 329185b4595SMarouene Boubakri 330185b4595SMarouene Boubakri static void *mobj_shm_get_va(struct mobj *mobj, size_t offset) 331185b4595SMarouene Boubakri { 332185b4595SMarouene Boubakri struct mobj_shm *m = to_mobj_shm(mobj); 333185b4595SMarouene Boubakri 334185b4595SMarouene Boubakri if (offset >= mobj->size) 335185b4595SMarouene Boubakri return NULL; 336185b4595SMarouene Boubakri 337185b4595SMarouene Boubakri return phys_to_virt(m->pa + offset, MEM_AREA_NSEC_SHM); 338185b4595SMarouene Boubakri } 339185b4595SMarouene Boubakri 340185b4595SMarouene Boubakri static TEE_Result mobj_shm_get_pa(struct mobj *mobj, size_t offs, 341185b4595SMarouene Boubakri size_t granule, paddr_t *pa) 342185b4595SMarouene Boubakri { 343185b4595SMarouene Boubakri struct mobj_shm *m = to_mobj_shm(mobj); 344185b4595SMarouene Boubakri paddr_t p; 345185b4595SMarouene Boubakri 346185b4595SMarouene Boubakri if (!pa || offs >= mobj->size) 347185b4595SMarouene Boubakri return TEE_ERROR_GENERIC; 348185b4595SMarouene Boubakri 349185b4595SMarouene Boubakri p = m->pa + offs; 350185b4595SMarouene Boubakri 351185b4595SMarouene Boubakri if (granule) { 352185b4595SMarouene Boubakri if (granule != SMALL_PAGE_SIZE && 353185b4595SMarouene Boubakri granule != CORE_MMU_PGDIR_SIZE) 354185b4595SMarouene Boubakri return TEE_ERROR_GENERIC; 355185b4595SMarouene Boubakri p &= ~(granule - 1); 356185b4595SMarouene Boubakri } 357185b4595SMarouene Boubakri 358185b4595SMarouene Boubakri *pa = p; 359185b4595SMarouene Boubakri return TEE_SUCCESS; 360185b4595SMarouene Boubakri } 361185b4595SMarouene Boubakri DECLARE_KEEP_PAGER(mobj_shm_get_pa); 362185b4595SMarouene Boubakri 363185b4595SMarouene Boubakri static size_t mobj_shm_get_phys_offs(struct mobj *mobj, size_t granule) 364185b4595SMarouene Boubakri { 365185b4595SMarouene Boubakri assert(IS_POWER_OF_TWO(granule)); 366185b4595SMarouene Boubakri return to_mobj_shm(mobj)->pa & (granule - 1); 367185b4595SMarouene Boubakri } 368185b4595SMarouene Boubakri 369185b4595SMarouene Boubakri static bool mobj_shm_matches(struct mobj *mobj __unused, enum buf_is_attr attr) 370185b4595SMarouene Boubakri { 371185b4595SMarouene Boubakri return attr == CORE_MEM_NSEC_SHM || attr == CORE_MEM_NON_SEC; 372185b4595SMarouene Boubakri } 373185b4595SMarouene Boubakri 374185b4595SMarouene Boubakri static void mobj_shm_free(struct mobj *mobj) 375185b4595SMarouene Boubakri { 376185b4595SMarouene Boubakri struct mobj_shm *m = to_mobj_shm(mobj); 377185b4595SMarouene Boubakri 378185b4595SMarouene Boubakri free(m); 379185b4595SMarouene Boubakri } 380185b4595SMarouene Boubakri 381185b4595SMarouene Boubakri static uint64_t mobj_shm_get_cookie(struct mobj *mobj) 382185b4595SMarouene Boubakri { 383185b4595SMarouene Boubakri return to_mobj_shm(mobj)->cookie; 384185b4595SMarouene Boubakri } 385185b4595SMarouene Boubakri 386*00361c18SJens Wiklander /* 387*00361c18SJens Wiklander * Note: this variable is weak just to ease breaking its dependency chain 388*00361c18SJens Wiklander * when added to the unpaged area. 389*00361c18SJens Wiklander */ 390*00361c18SJens Wiklander const struct mobj_ops mobj_shm_ops __weak __rodata_unpaged("mobj_shm_ops") = { 391185b4595SMarouene Boubakri .get_va = mobj_shm_get_va, 392185b4595SMarouene Boubakri .get_pa = mobj_shm_get_pa, 393185b4595SMarouene Boubakri .get_phys_offs = mobj_shm_get_phys_offs, 394185b4595SMarouene Boubakri .matches = mobj_shm_matches, 395185b4595SMarouene Boubakri .free = mobj_shm_free, 396185b4595SMarouene Boubakri .get_cookie = mobj_shm_get_cookie, 397185b4595SMarouene Boubakri }; 398185b4595SMarouene Boubakri 399185b4595SMarouene Boubakri static struct mobj_shm *to_mobj_shm(struct mobj *mobj) 400185b4595SMarouene Boubakri { 401185b4595SMarouene Boubakri assert(mobj->ops == &mobj_shm_ops); 402185b4595SMarouene Boubakri return container_of(mobj, struct mobj_shm, mobj); 403185b4595SMarouene Boubakri } 404185b4595SMarouene Boubakri 405185b4595SMarouene Boubakri struct mobj *mobj_shm_alloc(paddr_t pa, size_t size, uint64_t cookie) 406185b4595SMarouene Boubakri { 407185b4595SMarouene Boubakri struct mobj_shm *m; 408185b4595SMarouene Boubakri 409185b4595SMarouene Boubakri if (!core_pbuf_is(CORE_MEM_NSEC_SHM, pa, size)) 410185b4595SMarouene Boubakri return NULL; 411185b4595SMarouene Boubakri 412185b4595SMarouene Boubakri m = calloc(1, sizeof(*m)); 413185b4595SMarouene Boubakri if (!m) 414185b4595SMarouene Boubakri return NULL; 415185b4595SMarouene Boubakri 416185b4595SMarouene Boubakri m->mobj.size = size; 417185b4595SMarouene Boubakri m->mobj.ops = &mobj_shm_ops; 418185b4595SMarouene Boubakri refcount_set(&m->mobj.refc, 1); 419185b4595SMarouene Boubakri m->pa = pa; 420185b4595SMarouene Boubakri m->cookie = cookie; 421185b4595SMarouene Boubakri 422185b4595SMarouene Boubakri return &m->mobj; 423185b4595SMarouene Boubakri } 424185b4595SMarouene Boubakri 425185b4595SMarouene Boubakri #ifdef CFG_PAGED_USER_TA 426185b4595SMarouene Boubakri /* 427185b4595SMarouene Boubakri * mobj_seccpy_shm implementation 428185b4595SMarouene Boubakri */ 429185b4595SMarouene Boubakri 430185b4595SMarouene Boubakri struct mobj_seccpy_shm { 431185b4595SMarouene Boubakri struct user_ta_ctx *utc; 432185b4595SMarouene Boubakri vaddr_t va; 433185b4595SMarouene Boubakri struct mobj mobj; 434185b4595SMarouene Boubakri struct fobj *fobj; 435185b4595SMarouene Boubakri }; 436185b4595SMarouene Boubakri 437185b4595SMarouene Boubakri static bool __maybe_unused mobj_is_seccpy_shm(struct mobj *mobj); 438185b4595SMarouene Boubakri 439185b4595SMarouene Boubakri static struct mobj_seccpy_shm *to_mobj_seccpy_shm(struct mobj *mobj) 440185b4595SMarouene Boubakri { 441185b4595SMarouene Boubakri assert(mobj_is_seccpy_shm(mobj)); 442185b4595SMarouene Boubakri return container_of(mobj, struct mobj_seccpy_shm, mobj); 443185b4595SMarouene Boubakri } 444185b4595SMarouene Boubakri 445185b4595SMarouene Boubakri static void *mobj_seccpy_shm_get_va(struct mobj *mobj, size_t offs) 446185b4595SMarouene Boubakri { 447185b4595SMarouene Boubakri struct mobj_seccpy_shm *m = to_mobj_seccpy_shm(mobj); 448185b4595SMarouene Boubakri 449185b4595SMarouene Boubakri if (&m->utc->ta_ctx.ts_ctx != thread_get_tsd()->ctx) 450185b4595SMarouene Boubakri return NULL; 451185b4595SMarouene Boubakri 452185b4595SMarouene Boubakri if (offs >= mobj->size) 453185b4595SMarouene Boubakri return NULL; 454185b4595SMarouene Boubakri return (void *)(m->va + offs); 455185b4595SMarouene Boubakri } 456185b4595SMarouene Boubakri 457185b4595SMarouene Boubakri static bool mobj_seccpy_shm_matches(struct mobj *mobj __maybe_unused, 458185b4595SMarouene Boubakri enum buf_is_attr attr) 459185b4595SMarouene Boubakri { 460185b4595SMarouene Boubakri assert(mobj_is_seccpy_shm(mobj)); 461185b4595SMarouene Boubakri 462185b4595SMarouene Boubakri return attr == CORE_MEM_SEC || attr == CORE_MEM_TEE_RAM; 463185b4595SMarouene Boubakri } 464185b4595SMarouene Boubakri 465185b4595SMarouene Boubakri static void mobj_seccpy_shm_free(struct mobj *mobj) 466185b4595SMarouene Boubakri { 467185b4595SMarouene Boubakri struct mobj_seccpy_shm *m = to_mobj_seccpy_shm(mobj); 468185b4595SMarouene Boubakri 469185b4595SMarouene Boubakri tee_pager_rem_um_region(&m->utc->uctx, m->va, mobj->size); 470185b4595SMarouene Boubakri vm_rem_rwmem(&m->utc->uctx, mobj, m->va); 471185b4595SMarouene Boubakri fobj_put(m->fobj); 472185b4595SMarouene Boubakri free(m); 473185b4595SMarouene Boubakri } 474185b4595SMarouene Boubakri 475185b4595SMarouene Boubakri static struct fobj *mobj_seccpy_shm_get_fobj(struct mobj *mobj) 476185b4595SMarouene Boubakri { 477185b4595SMarouene Boubakri return fobj_get(to_mobj_seccpy_shm(mobj)->fobj); 478185b4595SMarouene Boubakri } 479185b4595SMarouene Boubakri 480*00361c18SJens Wiklander /* 481*00361c18SJens Wiklander * Note: this variable is weak just to ease breaking its dependency chain 482*00361c18SJens Wiklander * when added to the unpaged area. 483*00361c18SJens Wiklander */ 484*00361c18SJens Wiklander const struct mobj_ops mobj_seccpy_shm_ops 485*00361c18SJens Wiklander __weak __rodata_unpaged("mobj_seccpy_shm_ops") = { 486185b4595SMarouene Boubakri .get_va = mobj_seccpy_shm_get_va, 487185b4595SMarouene Boubakri .matches = mobj_seccpy_shm_matches, 488185b4595SMarouene Boubakri .free = mobj_seccpy_shm_free, 489185b4595SMarouene Boubakri .get_fobj = mobj_seccpy_shm_get_fobj, 490185b4595SMarouene Boubakri }; 491185b4595SMarouene Boubakri 492185b4595SMarouene Boubakri static bool mobj_is_seccpy_shm(struct mobj *mobj) 493185b4595SMarouene Boubakri { 494185b4595SMarouene Boubakri return mobj && mobj->ops == &mobj_seccpy_shm_ops; 495185b4595SMarouene Boubakri } 496185b4595SMarouene Boubakri 497185b4595SMarouene Boubakri struct mobj *mobj_seccpy_shm_alloc(size_t size) 498185b4595SMarouene Boubakri { 499185b4595SMarouene Boubakri struct thread_specific_data *tsd = thread_get_tsd(); 500185b4595SMarouene Boubakri struct mobj_seccpy_shm *m; 501185b4595SMarouene Boubakri struct user_ta_ctx *utc; 502185b4595SMarouene Boubakri vaddr_t va = 0; 503185b4595SMarouene Boubakri 504185b4595SMarouene Boubakri if (!is_user_ta_ctx(tsd->ctx)) 505185b4595SMarouene Boubakri return NULL; 506185b4595SMarouene Boubakri utc = to_user_ta_ctx(tsd->ctx); 507185b4595SMarouene Boubakri 508185b4595SMarouene Boubakri m = calloc(1, sizeof(*m)); 509185b4595SMarouene Boubakri if (!m) 510185b4595SMarouene Boubakri return NULL; 511185b4595SMarouene Boubakri 512185b4595SMarouene Boubakri m->mobj.size = size; 513185b4595SMarouene Boubakri m->mobj.ops = &mobj_seccpy_shm_ops; 514185b4595SMarouene Boubakri refcount_set(&m->mobj.refc, 1); 515185b4595SMarouene Boubakri 516185b4595SMarouene Boubakri if (vm_add_rwmem(&utc->uctx, &m->mobj, &va) != TEE_SUCCESS) 517185b4595SMarouene Boubakri goto bad; 518185b4595SMarouene Boubakri 519185b4595SMarouene Boubakri m->fobj = fobj_rw_paged_alloc(ROUNDUP(size, SMALL_PAGE_SIZE) / 520185b4595SMarouene Boubakri SMALL_PAGE_SIZE); 521d5ad7ccfSJens Wiklander if (tee_pager_add_um_region(&utc->uctx, va, m->fobj, 522185b4595SMarouene Boubakri TEE_MATTR_PRW | TEE_MATTR_URW)) 523185b4595SMarouene Boubakri goto bad; 524185b4595SMarouene Boubakri 525185b4595SMarouene Boubakri m->va = va; 526185b4595SMarouene Boubakri m->utc = to_user_ta_ctx(tsd->ctx); 527185b4595SMarouene Boubakri return &m->mobj; 528185b4595SMarouene Boubakri bad: 529185b4595SMarouene Boubakri if (va) 530185b4595SMarouene Boubakri vm_rem_rwmem(&utc->uctx, &m->mobj, va); 531185b4595SMarouene Boubakri fobj_put(m->fobj); 532185b4595SMarouene Boubakri free(m); 533185b4595SMarouene Boubakri return NULL; 534185b4595SMarouene Boubakri } 535185b4595SMarouene Boubakri 536185b4595SMarouene Boubakri 537185b4595SMarouene Boubakri #endif /*CFG_PAGED_USER_TA*/ 538185b4595SMarouene Boubakri 539185b4595SMarouene Boubakri struct mobj_with_fobj { 540185b4595SMarouene Boubakri struct fobj *fobj; 541185b4595SMarouene Boubakri struct file *file; 542185b4595SMarouene Boubakri struct mobj mobj; 543185b4595SMarouene Boubakri }; 544185b4595SMarouene Boubakri 545*00361c18SJens Wiklander const struct mobj_ops mobj_with_fobj_ops; 546185b4595SMarouene Boubakri 547185b4595SMarouene Boubakri struct mobj *mobj_with_fobj_alloc(struct fobj *fobj, struct file *file) 548185b4595SMarouene Boubakri { 549185b4595SMarouene Boubakri struct mobj_with_fobj *m = NULL; 550185b4595SMarouene Boubakri 551185b4595SMarouene Boubakri if (!fobj) 552185b4595SMarouene Boubakri return NULL; 553185b4595SMarouene Boubakri 554185b4595SMarouene Boubakri m = calloc(1, sizeof(*m)); 555185b4595SMarouene Boubakri if (!m) 556185b4595SMarouene Boubakri return NULL; 557185b4595SMarouene Boubakri 558185b4595SMarouene Boubakri m->mobj.ops = &mobj_with_fobj_ops; 559185b4595SMarouene Boubakri refcount_set(&m->mobj.refc, 1); 560185b4595SMarouene Boubakri m->mobj.size = fobj->num_pages * SMALL_PAGE_SIZE; 561185b4595SMarouene Boubakri m->mobj.phys_granule = SMALL_PAGE_SIZE; 562185b4595SMarouene Boubakri m->fobj = fobj_get(fobj); 563185b4595SMarouene Boubakri m->file = file_get(file); 564185b4595SMarouene Boubakri 565185b4595SMarouene Boubakri return &m->mobj; 566185b4595SMarouene Boubakri } 567185b4595SMarouene Boubakri 568185b4595SMarouene Boubakri static struct mobj_with_fobj *to_mobj_with_fobj(struct mobj *mobj) 569185b4595SMarouene Boubakri { 570185b4595SMarouene Boubakri assert(mobj && mobj->ops == &mobj_with_fobj_ops); 571185b4595SMarouene Boubakri 572185b4595SMarouene Boubakri return container_of(mobj, struct mobj_with_fobj, mobj); 573185b4595SMarouene Boubakri } 574185b4595SMarouene Boubakri 575185b4595SMarouene Boubakri static bool mobj_with_fobj_matches(struct mobj *mobj __maybe_unused, 576185b4595SMarouene Boubakri enum buf_is_attr attr) 577185b4595SMarouene Boubakri { 578185b4595SMarouene Boubakri assert(to_mobj_with_fobj(mobj)); 579185b4595SMarouene Boubakri 580185b4595SMarouene Boubakri /* 581185b4595SMarouene Boubakri * All fobjs are supposed to be mapped secure so classify it as 582185b4595SMarouene Boubakri * CORE_MEM_SEC. Stay out of CORE_MEM_TEE_RAM etc, if that information 583185b4595SMarouene Boubakri * needed it can probably be carried in another way than to put the 584185b4595SMarouene Boubakri * burden directly on fobj. 585185b4595SMarouene Boubakri */ 586185b4595SMarouene Boubakri return attr == CORE_MEM_SEC; 587185b4595SMarouene Boubakri } 588185b4595SMarouene Boubakri 589185b4595SMarouene Boubakri static void mobj_with_fobj_free(struct mobj *mobj) 590185b4595SMarouene Boubakri { 591185b4595SMarouene Boubakri struct mobj_with_fobj *m = to_mobj_with_fobj(mobj); 592185b4595SMarouene Boubakri 593185b4595SMarouene Boubakri fobj_put(m->fobj); 594185b4595SMarouene Boubakri file_put(m->file); 595185b4595SMarouene Boubakri free(m); 596185b4595SMarouene Boubakri } 597185b4595SMarouene Boubakri 598185b4595SMarouene Boubakri static struct fobj *mobj_with_fobj_get_fobj(struct mobj *mobj) 599185b4595SMarouene Boubakri { 600185b4595SMarouene Boubakri return fobj_get(to_mobj_with_fobj(mobj)->fobj); 601185b4595SMarouene Boubakri } 602185b4595SMarouene Boubakri 603185b4595SMarouene Boubakri static TEE_Result mobj_with_fobj_get_cattr(struct mobj *mobj __unused, 604185b4595SMarouene Boubakri uint32_t *cattr) 605185b4595SMarouene Boubakri { 606185b4595SMarouene Boubakri if (!cattr) 607185b4595SMarouene Boubakri return TEE_ERROR_GENERIC; 608185b4595SMarouene Boubakri 609185b4595SMarouene Boubakri /* All fobjs are mapped as normal cached memory */ 610185b4595SMarouene Boubakri *cattr = TEE_MATTR_CACHE_CACHED; 611185b4595SMarouene Boubakri 612185b4595SMarouene Boubakri return TEE_SUCCESS; 613185b4595SMarouene Boubakri } 614185b4595SMarouene Boubakri 615185b4595SMarouene Boubakri static TEE_Result mobj_with_fobj_get_pa(struct mobj *mobj, size_t offs, 616185b4595SMarouene Boubakri size_t granule, paddr_t *pa) 617185b4595SMarouene Boubakri { 618185b4595SMarouene Boubakri struct mobj_with_fobj *f = to_mobj_with_fobj(mobj); 619185b4595SMarouene Boubakri paddr_t p = 0; 620185b4595SMarouene Boubakri 621185b4595SMarouene Boubakri if (!f->fobj->ops->get_pa) { 622185b4595SMarouene Boubakri assert(mobj_is_paged(mobj)); 623185b4595SMarouene Boubakri return TEE_ERROR_NOT_SUPPORTED; 624185b4595SMarouene Boubakri } 625185b4595SMarouene Boubakri 626185b4595SMarouene Boubakri p = f->fobj->ops->get_pa(f->fobj, offs / SMALL_PAGE_SIZE) + 627185b4595SMarouene Boubakri offs % SMALL_PAGE_SIZE; 628185b4595SMarouene Boubakri 629185b4595SMarouene Boubakri if (granule) { 630185b4595SMarouene Boubakri if (granule != SMALL_PAGE_SIZE && 631185b4595SMarouene Boubakri granule != CORE_MMU_PGDIR_SIZE) 632185b4595SMarouene Boubakri return TEE_ERROR_GENERIC; 633185b4595SMarouene Boubakri p &= ~(granule - 1); 634185b4595SMarouene Boubakri } 635185b4595SMarouene Boubakri 636185b4595SMarouene Boubakri *pa = p; 637185b4595SMarouene Boubakri 638185b4595SMarouene Boubakri return TEE_SUCCESS; 639185b4595SMarouene Boubakri } 640185b4595SMarouene Boubakri DECLARE_KEEP_PAGER(mobj_with_fobj_get_pa); 641185b4595SMarouene Boubakri 642*00361c18SJens Wiklander /* 643*00361c18SJens Wiklander * Note: this variable is weak just to ease breaking its dependency chain 644*00361c18SJens Wiklander * when added to the unpaged area. 645*00361c18SJens Wiklander */ 646*00361c18SJens Wiklander const struct mobj_ops mobj_with_fobj_ops 647*00361c18SJens Wiklander __weak __rodata_unpaged("mobj_with_fobj_ops") = { 648185b4595SMarouene Boubakri .matches = mobj_with_fobj_matches, 649185b4595SMarouene Boubakri .free = mobj_with_fobj_free, 650185b4595SMarouene Boubakri .get_fobj = mobj_with_fobj_get_fobj, 651185b4595SMarouene Boubakri .get_cattr = mobj_with_fobj_get_cattr, 652185b4595SMarouene Boubakri .get_pa = mobj_with_fobj_get_pa, 653185b4595SMarouene Boubakri }; 654185b4595SMarouene Boubakri 655185b4595SMarouene Boubakri #ifdef CFG_PAGED_USER_TA 656185b4595SMarouene Boubakri bool mobj_is_paged(struct mobj *mobj) 657185b4595SMarouene Boubakri { 658185b4595SMarouene Boubakri if (mobj->ops == &mobj_seccpy_shm_ops) 659185b4595SMarouene Boubakri return true; 660185b4595SMarouene Boubakri 661185b4595SMarouene Boubakri if (mobj->ops == &mobj_with_fobj_ops && 662185b4595SMarouene Boubakri !to_mobj_with_fobj(mobj)->fobj->ops->get_pa) 663185b4595SMarouene Boubakri return true; 664185b4595SMarouene Boubakri 665185b4595SMarouene Boubakri return false; 666185b4595SMarouene Boubakri } 667185b4595SMarouene Boubakri #endif /*CFG_PAGED_USER_TA*/ 668185b4595SMarouene Boubakri 669185b4595SMarouene Boubakri static TEE_Result mobj_init(void) 670185b4595SMarouene Boubakri { 671185b4595SMarouene Boubakri mobj_sec_ddr = mobj_phys_alloc(tee_mm_sec_ddr.lo, 672185b4595SMarouene Boubakri tee_mm_sec_ddr.hi - tee_mm_sec_ddr.lo, 673185b4595SMarouene Boubakri OPTEE_SMC_SHM_CACHED, CORE_MEM_TA_RAM); 674185b4595SMarouene Boubakri if (!mobj_sec_ddr) 675185b4595SMarouene Boubakri panic("Failed to register secure ta ram"); 676185b4595SMarouene Boubakri 677185b4595SMarouene Boubakri mobj_tee_ram = mobj_phys_alloc(TEE_RAM_START, 678185b4595SMarouene Boubakri VCORE_UNPG_RW_PA + VCORE_UNPG_RW_SZ - 679185b4595SMarouene Boubakri TEE_RAM_START, 680185b4595SMarouene Boubakri TEE_MATTR_CACHE_CACHED, 681185b4595SMarouene Boubakri CORE_MEM_TEE_RAM); 682185b4595SMarouene Boubakri if (!mobj_tee_ram) 683185b4595SMarouene Boubakri panic("Failed to register tee ram"); 684185b4595SMarouene Boubakri 685185b4595SMarouene Boubakri return TEE_SUCCESS; 686185b4595SMarouene Boubakri } 687185b4595SMarouene Boubakri 688185b4595SMarouene Boubakri driver_init_late(mobj_init); 689