1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2016-2022, Linaro Limited 4 */ 5 6 #include <assert.h> 7 #include <config.h> 8 #include <initcall.h> 9 #include <keep.h> 10 #include <kernel/linker.h> 11 #include <kernel/mutex.h> 12 #include <kernel/panic.h> 13 #include <kernel/refcount.h> 14 #include <kernel/spinlock.h> 15 #include <mm/core_mmu.h> 16 #include <mm/mobj.h> 17 #include <mm/tee_pager.h> 18 #include <optee_msg.h> 19 #include <stdlib.h> 20 #include <tee_api_types.h> 21 #include <types_ext.h> 22 #include <util.h> 23 24 struct mobj *mobj_tee_ram_rx; 25 struct mobj *mobj_tee_ram_rw; 26 27 /* 28 * mobj_phys implementation 29 */ 30 31 struct mobj_phys { 32 struct mobj mobj; 33 enum buf_is_attr battr; 34 /* Defined by TEE_MATTR_MEM_TYPE_* in tee_mmu_types.h */ 35 uint32_t mem_type; 36 vaddr_t va; 37 paddr_t pa; 38 }; 39 40 static struct mobj_phys *to_mobj_phys(struct mobj *mobj); 41 42 static void *mobj_phys_get_va(struct mobj *mobj, size_t offset, size_t len) 43 { 44 struct mobj_phys *moph = to_mobj_phys(mobj); 45 46 if (!moph->va || !mobj_check_offset_and_len(mobj, offset, len)) 47 return NULL; 48 49 return (void *)(moph->va + offset); 50 } 51 52 static TEE_Result mobj_phys_get_pa(struct mobj *mobj, size_t offs, 53 size_t granule, paddr_t *pa) 54 { 55 struct mobj_phys *moph = to_mobj_phys(mobj); 56 paddr_t p; 57 58 if (!pa) 59 return TEE_ERROR_GENERIC; 60 61 p = moph->pa + offs; 62 63 if (granule) { 64 if (granule != SMALL_PAGE_SIZE && 65 granule != CORE_MMU_PGDIR_SIZE) 66 return TEE_ERROR_GENERIC; 67 p &= ~(granule - 1); 68 } 69 70 *pa = p; 71 return TEE_SUCCESS; 72 } 73 DECLARE_KEEP_PAGER(mobj_phys_get_pa); 74 75 static TEE_Result mobj_phys_get_mem_type(struct mobj *mobj, uint32_t *mem_type) 76 { 77 struct mobj_phys *moph = to_mobj_phys(mobj); 78 79 if (!mem_type) 80 return TEE_ERROR_GENERIC; 81 82 *mem_type = moph->mem_type; 83 return TEE_SUCCESS; 84 } 85 86 static bool mobj_phys_matches(struct mobj *mobj, enum buf_is_attr attr) 87 { 88 struct mobj_phys *moph = to_mobj_phys(mobj); 89 enum buf_is_attr a; 90 91 a = moph->battr; 92 93 switch (attr) { 94 case CORE_MEM_SEC: 95 return a == CORE_MEM_SEC || a == CORE_MEM_TEE_RAM || 96 a == CORE_MEM_SDP_MEM; 97 case CORE_MEM_NON_SEC: 98 return a == CORE_MEM_NSEC_SHM; 99 case CORE_MEM_TEE_RAM: 100 case CORE_MEM_NSEC_SHM: 101 case CORE_MEM_SDP_MEM: 102 return attr == a; 103 default: 104 return false; 105 } 106 } 107 108 static void mobj_phys_free(struct mobj *mobj) 109 { 110 struct mobj_phys *moph = to_mobj_phys(mobj); 111 112 free(moph); 113 } 114 115 /* 116 * Note: this variable is weak just to ease breaking its dependency chain 117 * when added to the unpaged area. 118 */ 119 const struct mobj_ops mobj_phys_ops 120 __weak __relrodata_unpaged("mobj_phys_ops") = { 121 .get_va = mobj_phys_get_va, 122 .get_pa = mobj_phys_get_pa, 123 .get_phys_offs = NULL, /* only offset 0 */ 124 .get_mem_type = mobj_phys_get_mem_type, 125 .matches = mobj_phys_matches, 126 .free = mobj_phys_free, 127 }; 128 129 static struct mobj_phys *to_mobj_phys(struct mobj *mobj) 130 { 131 assert(mobj->ops == &mobj_phys_ops); 132 return container_of(mobj, struct mobj_phys, mobj); 133 } 134 135 static struct mobj *mobj_phys_init(paddr_t pa, size_t size, uint32_t mem_type, 136 enum buf_is_attr battr, 137 enum teecore_memtypes area_type) 138 { 139 void *va = NULL; 140 struct mobj_phys *moph = NULL; 141 struct tee_mmap_region *map = NULL; 142 143 if ((pa & CORE_MMU_USER_PARAM_MASK) || 144 (size & CORE_MMU_USER_PARAM_MASK)) { 145 DMSG("Expect %#x alignment", CORE_MMU_USER_PARAM_SIZE); 146 return NULL; 147 } 148 149 if (pa) { 150 va = phys_to_virt(pa, area_type, size); 151 } else { 152 map = core_mmu_find_mapping_exclusive(area_type, size); 153 if (!map) 154 return NULL; 155 156 pa = map->pa; 157 va = (void *)map->va; 158 } 159 160 /* Only SDP memory may not have a virtual address */ 161 if (!va && battr != CORE_MEM_SDP_MEM) 162 return NULL; 163 164 moph = calloc(1, sizeof(*moph)); 165 if (!moph) 166 return NULL; 167 168 moph->battr = battr; 169 moph->mem_type = mem_type; 170 moph->mobj.size = size; 171 moph->mobj.ops = &mobj_phys_ops; 172 refcount_set(&moph->mobj.refc, 1); 173 moph->pa = pa; 174 moph->va = (vaddr_t)va; 175 176 return &moph->mobj; 177 } 178 179 struct mobj *mobj_phys_alloc(paddr_t pa, size_t size, uint32_t mem_type, 180 enum buf_is_attr battr) 181 { 182 enum teecore_memtypes area_type; 183 184 switch (battr) { 185 case CORE_MEM_NSEC_SHM: 186 area_type = MEM_AREA_NSEC_SHM; 187 break; 188 case CORE_MEM_SDP_MEM: 189 area_type = MEM_AREA_SDP_MEM; 190 break; 191 default: 192 DMSG("can't allocate with specified attribute"); 193 return NULL; 194 } 195 196 return mobj_phys_init(pa, size, mem_type, battr, area_type); 197 } 198 199 /* 200 * mobj_virt implementation 201 */ 202 203 static void mobj_virt_assert_type(struct mobj *mobj); 204 205 static void *mobj_virt_get_va(struct mobj *mobj, size_t offset, 206 size_t len __maybe_unused) 207 { 208 mobj_virt_assert_type(mobj); 209 assert(mobj_check_offset_and_len(mobj, offset, len)); 210 211 return (void *)(vaddr_t)offset; 212 } 213 214 /* 215 * Note: this variable is weak just to ease breaking its dependency chain 216 * when added to the unpaged area. 217 */ 218 const struct mobj_ops mobj_virt_ops 219 __weak __relrodata_unpaged("mobj_virt_ops") = { 220 .get_va = mobj_virt_get_va, 221 }; 222 223 static void mobj_virt_assert_type(struct mobj *mobj __maybe_unused) 224 { 225 assert(mobj->ops == &mobj_virt_ops); 226 } 227 228 struct mobj mobj_virt = { .ops = &mobj_virt_ops, .size = SIZE_MAX }; 229 230 /* 231 * mobj_shm implementation. mobj_shm represents buffer in predefined shm region 232 * - it is physically contiguous. 233 * - it is identified in static physical layout as MEM_AREA_NSEC_SHM. 234 * - it creates mobjs that match specific CORE_MEM_NSEC_SHM and non secure 235 * generic CORE_MEM_NON_SEC. 236 */ 237 238 struct mobj_shm { 239 struct mobj mobj; 240 paddr_t pa; 241 uint64_t cookie; 242 }; 243 244 static struct mobj_shm *to_mobj_shm(struct mobj *mobj); 245 246 static void *mobj_shm_get_va(struct mobj *mobj, size_t offset, size_t len) 247 { 248 struct mobj_shm *m = to_mobj_shm(mobj); 249 250 if (!mobj_check_offset_and_len(mobj, offset, len)) 251 return NULL; 252 253 return phys_to_virt(m->pa + offset, MEM_AREA_NSEC_SHM, 254 mobj->size - offset); 255 } 256 257 static TEE_Result mobj_shm_get_pa(struct mobj *mobj, size_t offs, 258 size_t granule, paddr_t *pa) 259 { 260 struct mobj_shm *m = to_mobj_shm(mobj); 261 paddr_t p; 262 263 if (!pa || offs >= mobj->size) 264 return TEE_ERROR_GENERIC; 265 266 p = m->pa + offs; 267 268 if (granule) { 269 if (granule != SMALL_PAGE_SIZE && 270 granule != CORE_MMU_PGDIR_SIZE) 271 return TEE_ERROR_GENERIC; 272 p &= ~(granule - 1); 273 } 274 275 *pa = p; 276 return TEE_SUCCESS; 277 } 278 DECLARE_KEEP_PAGER(mobj_shm_get_pa); 279 280 static size_t mobj_shm_get_phys_offs(struct mobj *mobj, size_t granule) 281 { 282 assert(IS_POWER_OF_TWO(granule)); 283 return to_mobj_shm(mobj)->pa & (granule - 1); 284 } 285 286 static bool mobj_shm_matches(struct mobj *mobj __unused, enum buf_is_attr attr) 287 { 288 return attr == CORE_MEM_NSEC_SHM || attr == CORE_MEM_NON_SEC; 289 } 290 291 static TEE_Result mobj_shm_get_mem_type(struct mobj *mobj __unused, 292 uint32_t *mem_type) 293 { 294 if (!mem_type) 295 return TEE_ERROR_GENERIC; 296 297 *mem_type = TEE_MATTR_MEM_TYPE_CACHED; 298 299 return TEE_SUCCESS; 300 } 301 302 static void mobj_shm_free(struct mobj *mobj) 303 { 304 struct mobj_shm *m = to_mobj_shm(mobj); 305 306 free(m); 307 } 308 309 static uint64_t mobj_shm_get_cookie(struct mobj *mobj) 310 { 311 return to_mobj_shm(mobj)->cookie; 312 } 313 314 /* 315 * Note: this variable is weak just to ease breaking its dependency chain 316 * when added to the unpaged area. 317 */ 318 const struct mobj_ops mobj_shm_ops 319 __weak __relrodata_unpaged("mobj_shm_ops") = { 320 .get_va = mobj_shm_get_va, 321 .get_pa = mobj_shm_get_pa, 322 .get_phys_offs = mobj_shm_get_phys_offs, 323 .get_mem_type = mobj_shm_get_mem_type, 324 .matches = mobj_shm_matches, 325 .free = mobj_shm_free, 326 .get_cookie = mobj_shm_get_cookie, 327 }; 328 329 static struct mobj_shm *to_mobj_shm(struct mobj *mobj) 330 { 331 assert(mobj->ops == &mobj_shm_ops); 332 return container_of(mobj, struct mobj_shm, mobj); 333 } 334 335 struct mobj *mobj_shm_alloc(paddr_t pa, size_t size, uint64_t cookie) 336 { 337 struct mobj_shm *m; 338 339 if (!core_pbuf_is(CORE_MEM_NSEC_SHM, pa, size)) 340 return NULL; 341 342 m = calloc(1, sizeof(*m)); 343 if (!m) 344 return NULL; 345 346 m->mobj.size = size; 347 m->mobj.ops = &mobj_shm_ops; 348 m->mobj.phys_granule = SMALL_PAGE_SIZE; 349 refcount_set(&m->mobj.refc, 1); 350 m->pa = pa; 351 m->cookie = cookie; 352 353 return &m->mobj; 354 } 355 356 struct mobj_with_fobj { 357 struct fobj *fobj; 358 struct file *file; 359 struct mobj mobj; 360 uint8_t mem_type; 361 }; 362 363 const struct mobj_ops mobj_with_fobj_ops; 364 365 struct mobj *mobj_with_fobj_alloc(struct fobj *fobj, struct file *file, 366 uint32_t mem_type) 367 { 368 struct mobj_with_fobj *m = NULL; 369 370 assert(!(mem_type & ~TEE_MATTR_MEM_TYPE_MASK)); 371 372 if (!fobj) 373 return NULL; 374 if (mem_type > UINT8_MAX) 375 return NULL; 376 377 m = calloc(1, sizeof(*m)); 378 if (!m) 379 return NULL; 380 381 m->mobj.ops = &mobj_with_fobj_ops; 382 refcount_set(&m->mobj.refc, 1); 383 m->mobj.size = fobj->num_pages * SMALL_PAGE_SIZE; 384 m->mobj.phys_granule = SMALL_PAGE_SIZE; 385 m->fobj = fobj_get(fobj); 386 m->file = file_get(file); 387 m->mem_type = mem_type; 388 389 return &m->mobj; 390 } 391 392 static struct mobj_with_fobj *to_mobj_with_fobj(struct mobj *mobj) 393 { 394 assert(mobj && mobj->ops == &mobj_with_fobj_ops); 395 396 return container_of(mobj, struct mobj_with_fobj, mobj); 397 } 398 399 static bool mobj_with_fobj_matches(struct mobj *mobj __maybe_unused, 400 enum buf_is_attr attr) 401 { 402 assert(to_mobj_with_fobj(mobj)); 403 404 /* 405 * All fobjs are supposed to be mapped secure so classify it as 406 * CORE_MEM_SEC. Stay out of CORE_MEM_TEE_RAM etc, if that information 407 * needed it can probably be carried in another way than to put the 408 * burden directly on fobj. 409 */ 410 return attr == CORE_MEM_SEC; 411 } 412 413 static void mobj_with_fobj_free(struct mobj *mobj) 414 { 415 struct mobj_with_fobj *m = to_mobj_with_fobj(mobj); 416 417 fobj_put(m->fobj); 418 file_put(m->file); 419 free(m); 420 } 421 422 static struct fobj *mobj_with_fobj_get_fobj(struct mobj *mobj) 423 { 424 return fobj_get(to_mobj_with_fobj(mobj)->fobj); 425 } 426 427 static TEE_Result mobj_with_fobj_get_mem_type(struct mobj *mobj, 428 uint32_t *mem_type) 429 { 430 struct mobj_with_fobj *m = to_mobj_with_fobj(mobj); 431 432 if (!mem_type) 433 return TEE_ERROR_GENERIC; 434 435 *mem_type = m->mem_type; 436 437 return TEE_SUCCESS; 438 } 439 440 static TEE_Result mobj_with_fobj_get_pa(struct mobj *mobj, size_t offs, 441 size_t granule, paddr_t *pa) 442 { 443 struct mobj_with_fobj *f = to_mobj_with_fobj(mobj); 444 paddr_t p = 0; 445 446 if (!f->fobj->ops->get_pa) { 447 assert(mobj_is_paged(mobj)); 448 return TEE_ERROR_NOT_SUPPORTED; 449 } 450 451 p = f->fobj->ops->get_pa(f->fobj, offs / SMALL_PAGE_SIZE) + 452 offs % SMALL_PAGE_SIZE; 453 454 if (granule) { 455 if (granule != SMALL_PAGE_SIZE && 456 granule != CORE_MMU_PGDIR_SIZE) 457 return TEE_ERROR_GENERIC; 458 p &= ~(granule - 1); 459 } 460 461 *pa = p; 462 463 return TEE_SUCCESS; 464 } 465 DECLARE_KEEP_PAGER(mobj_with_fobj_get_pa); 466 467 /* 468 * Note: this variable is weak just to ease breaking its dependency chain 469 * when added to the unpaged area. 470 */ 471 const struct mobj_ops mobj_with_fobj_ops 472 __weak __relrodata_unpaged("mobj_with_fobj_ops") = { 473 .matches = mobj_with_fobj_matches, 474 .free = mobj_with_fobj_free, 475 .get_fobj = mobj_with_fobj_get_fobj, 476 .get_mem_type = mobj_with_fobj_get_mem_type, 477 .get_pa = mobj_with_fobj_get_pa, 478 }; 479 480 #ifdef CFG_PAGED_USER_TA 481 bool mobj_is_paged(struct mobj *mobj) 482 { 483 if (mobj->ops == &mobj_with_fobj_ops && 484 !to_mobj_with_fobj(mobj)->fobj->ops->get_pa) 485 return true; 486 487 return false; 488 } 489 #endif /*CFG_PAGED_USER_TA*/ 490 491 static TEE_Result mobj_init(void) 492 { 493 if (IS_ENABLED(CFG_CORE_RWDATA_NOEXEC)) { 494 mobj_tee_ram_rx = mobj_phys_init(0, 495 VCORE_UNPG_RX_SZ, 496 TEE_MATTR_MEM_TYPE_CACHED, 497 CORE_MEM_TEE_RAM, 498 MEM_AREA_TEE_RAM_RX); 499 if (!mobj_tee_ram_rx) 500 panic("Failed to register tee ram rx"); 501 502 mobj_tee_ram_rw = mobj_phys_init(0, 503 VCORE_UNPG_RW_SZ, 504 TEE_MATTR_MEM_TYPE_CACHED, 505 CORE_MEM_TEE_RAM, 506 MEM_AREA_TEE_RAM_RW_DATA); 507 if (!mobj_tee_ram_rw) 508 panic("Failed to register tee ram rw"); 509 } else { 510 mobj_tee_ram_rw = mobj_phys_init(TEE_RAM_START, 511 VCORE_UNPG_RW_PA + 512 VCORE_UNPG_RW_SZ - 513 VCORE_START_VA, 514 TEE_MATTR_MEM_TYPE_CACHED, 515 CORE_MEM_TEE_RAM, 516 MEM_AREA_TEE_RAM_RW_DATA); 517 if (!mobj_tee_ram_rw) 518 panic("Failed to register tee ram"); 519 520 mobj_tee_ram_rx = mobj_tee_ram_rw; 521 } 522 523 return TEE_SUCCESS; 524 } 525 526 driver_init_late(mobj_init); 527