1 /* 2 * Copyright (c) 2016, Linaro Limited 3 * Copyright (c) 2014, STMicroelectronics International N.V. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <arm.h> 30 #include <assert.h> 31 #include <keep.h> 32 #include <sys/queue.h> 33 #include <kernel/abort.h> 34 #include <kernel/panic.h> 35 #include <kernel/spinlock.h> 36 #include <kernel/tlb_helpers.h> 37 #include <kernel/tee_misc.h> 38 #include <kernel/tee_ta_manager.h> 39 #include <kernel/thread.h> 40 #include <mm/core_memprot.h> 41 #include <mm/tee_mm.h> 42 #include <mm/tee_pager.h> 43 #include <types_ext.h> 44 #include <stdlib.h> 45 #include <tee_api_defines.h> 46 #include <tee/tee_cryp_provider.h> 47 #include <trace.h> 48 #include <utee_defines.h> 49 #include <util.h> 50 51 #include "pager_private.h" 52 53 #define PAGER_AE_KEY_BITS 256 54 55 struct pager_rw_pstate { 56 uint64_t iv; 57 uint8_t tag[PAGER_AES_GCM_TAG_LEN]; 58 }; 59 60 enum area_type { 61 AREA_TYPE_RO, 62 AREA_TYPE_RW, 63 AREA_TYPE_LOCK, 64 }; 65 66 struct tee_pager_area { 67 union { 68 const uint8_t *hashes; 69 struct pager_rw_pstate *rwp; 70 } u; 71 uint8_t *store; 72 enum area_type type; 73 uint32_t flags; 74 vaddr_t base; 75 size_t size; 76 struct pgt *pgt; 77 TAILQ_ENTRY(tee_pager_area) link; 78 }; 79 80 TAILQ_HEAD(tee_pager_area_head, tee_pager_area); 81 82 static struct tee_pager_area_head tee_pager_area_head = 83 TAILQ_HEAD_INITIALIZER(tee_pager_area_head); 84 85 #define INVALID_PGIDX UINT_MAX 86 87 /* 88 * struct tee_pager_pmem - Represents a physical page used for paging. 89 * 90 * @pgidx an index of the entry in area->ti. 91 * @va_alias Virtual address where the physical page always is aliased. 92 * Used during remapping of the page when the content need to 93 * be updated before it's available at the new location. 94 * @area a pointer to the pager area 95 */ 96 struct tee_pager_pmem { 97 unsigned pgidx; 98 void *va_alias; 99 struct tee_pager_area *area; 100 TAILQ_ENTRY(tee_pager_pmem) link; 101 }; 102 103 /* The list of physical pages. The first page in the list is the oldest */ 104 TAILQ_HEAD(tee_pager_pmem_head, tee_pager_pmem); 105 106 static struct tee_pager_pmem_head tee_pager_pmem_head = 107 TAILQ_HEAD_INITIALIZER(tee_pager_pmem_head); 108 109 static struct tee_pager_pmem_head tee_pager_lock_pmem_head = 110 TAILQ_HEAD_INITIALIZER(tee_pager_lock_pmem_head); 111 112 static uint8_t pager_ae_key[PAGER_AE_KEY_BITS / 8]; 113 114 /* number of pages hidden */ 115 #define TEE_PAGER_NHIDE (tee_pager_npages / 3) 116 117 /* Number of registered physical pages, used hiding pages. */ 118 static size_t tee_pager_npages; 119 120 #ifdef CFG_WITH_STATS 121 static struct tee_pager_stats pager_stats; 122 123 static inline void incr_ro_hits(void) 124 { 125 pager_stats.ro_hits++; 126 } 127 128 static inline void incr_rw_hits(void) 129 { 130 pager_stats.rw_hits++; 131 } 132 133 static inline void incr_hidden_hits(void) 134 { 135 pager_stats.hidden_hits++; 136 } 137 138 static inline void incr_zi_released(void) 139 { 140 pager_stats.zi_released++; 141 } 142 143 static inline void incr_npages_all(void) 144 { 145 pager_stats.npages_all++; 146 } 147 148 static inline void set_npages(void) 149 { 150 pager_stats.npages = tee_pager_npages; 151 } 152 153 void tee_pager_get_stats(struct tee_pager_stats *stats) 154 { 155 *stats = pager_stats; 156 157 pager_stats.hidden_hits = 0; 158 pager_stats.ro_hits = 0; 159 pager_stats.rw_hits = 0; 160 pager_stats.zi_released = 0; 161 } 162 163 #else /* CFG_WITH_STATS */ 164 static inline void incr_ro_hits(void) { } 165 static inline void incr_rw_hits(void) { } 166 static inline void incr_hidden_hits(void) { } 167 static inline void incr_zi_released(void) { } 168 static inline void incr_npages_all(void) { } 169 static inline void set_npages(void) { } 170 171 void tee_pager_get_stats(struct tee_pager_stats *stats) 172 { 173 memset(stats, 0, sizeof(struct tee_pager_stats)); 174 } 175 #endif /* CFG_WITH_STATS */ 176 177 static struct pgt pager_core_pgt; 178 struct core_mmu_table_info tee_pager_tbl_info; 179 static struct core_mmu_table_info pager_alias_tbl_info; 180 181 static unsigned pager_spinlock = SPINLOCK_UNLOCK; 182 183 /* Defines the range of the alias area */ 184 static tee_mm_entry_t *pager_alias_area; 185 /* 186 * Physical pages are added in a stack like fashion to the alias area, 187 * @pager_alias_next_free gives the address of next free entry if 188 * @pager_alias_next_free is != 0 189 */ 190 static uintptr_t pager_alias_next_free; 191 192 static uint32_t pager_lock(void) 193 { 194 return cpu_spin_lock_xsave(&pager_spinlock); 195 } 196 197 static void pager_unlock(uint32_t exceptions) 198 { 199 cpu_spin_unlock_xrestore(&pager_spinlock, exceptions); 200 } 201 202 static void set_alias_area(tee_mm_entry_t *mm) 203 { 204 struct core_mmu_table_info *ti = &pager_alias_tbl_info; 205 size_t tbl_va_size; 206 unsigned idx; 207 unsigned last_idx; 208 vaddr_t smem = tee_mm_get_smem(mm); 209 size_t nbytes = tee_mm_get_bytes(mm); 210 211 DMSG("0x%" PRIxVA " - 0x%" PRIxVA, smem, smem + nbytes); 212 213 if (pager_alias_area) 214 panic("null pager_alias_area"); 215 216 if (!ti->num_entries && !core_mmu_find_table(smem, UINT_MAX, ti)) 217 panic("Can't find translation table"); 218 219 if ((1 << ti->shift) != SMALL_PAGE_SIZE) 220 panic("Unsupported page size in translation table"); 221 222 tbl_va_size = (1 << ti->shift) * ti->num_entries; 223 if (!core_is_buffer_inside(smem, nbytes, 224 ti->va_base, tbl_va_size)) { 225 EMSG("area 0x%" PRIxVA " len 0x%zx doesn't fit it translation table 0x%" PRIxVA " len 0x%zx", 226 smem, nbytes, ti->va_base, tbl_va_size); 227 panic(); 228 } 229 230 if (smem & SMALL_PAGE_MASK || nbytes & SMALL_PAGE_MASK) 231 panic("invalid area alignment"); 232 233 pager_alias_area = mm; 234 pager_alias_next_free = smem; 235 236 /* Clear all mapping in the alias area */ 237 idx = core_mmu_va2idx(ti, smem); 238 last_idx = core_mmu_va2idx(ti, smem + nbytes); 239 for (; idx < last_idx; idx++) 240 core_mmu_set_entry(ti, idx, 0, 0); 241 242 tlbi_mva_range(smem, nbytes, SMALL_PAGE_SIZE); 243 } 244 245 static void generate_ae_key(void) 246 { 247 if (rng_generate(pager_ae_key, sizeof(pager_ae_key)) != TEE_SUCCESS) 248 panic("failed to generate random"); 249 } 250 251 void tee_pager_init(tee_mm_entry_t *mm_alias) 252 { 253 set_alias_area(mm_alias); 254 generate_ae_key(); 255 } 256 257 static void *pager_add_alias_page(paddr_t pa) 258 { 259 unsigned idx; 260 struct core_mmu_table_info *ti = &pager_alias_tbl_info; 261 /* Alias pages mapped without write permission: runtime will care */ 262 uint32_t attr = TEE_MATTR_VALID_BLOCK | TEE_MATTR_GLOBAL | 263 (TEE_MATTR_CACHE_CACHED << TEE_MATTR_CACHE_SHIFT) | 264 TEE_MATTR_SECURE | TEE_MATTR_PR; 265 266 DMSG("0x%" PRIxPA, pa); 267 268 if (!pager_alias_next_free || !ti->num_entries) 269 panic("invalid alias entry"); 270 271 idx = core_mmu_va2idx(ti, pager_alias_next_free); 272 core_mmu_set_entry(ti, idx, pa, attr); 273 pgt_inc_used_entries(&pager_core_pgt); 274 pager_alias_next_free += SMALL_PAGE_SIZE; 275 if (pager_alias_next_free >= (tee_mm_get_smem(pager_alias_area) + 276 tee_mm_get_bytes(pager_alias_area))) 277 pager_alias_next_free = 0; 278 return (void *)core_mmu_idx2va(ti, idx); 279 } 280 281 static struct tee_pager_area *alloc_area(struct pgt *pgt, 282 vaddr_t base, size_t size, 283 uint32_t flags, const void *store, 284 const void *hashes) 285 { 286 struct tee_pager_area *area = calloc(1, sizeof(*area)); 287 enum area_type at; 288 tee_mm_entry_t *mm_store = NULL; 289 290 if (!area) 291 return NULL; 292 293 if (flags & (TEE_MATTR_PW | TEE_MATTR_UW)) { 294 if (flags & TEE_MATTR_LOCKED) { 295 at = AREA_TYPE_LOCK; 296 goto out; 297 } 298 mm_store = tee_mm_alloc(&tee_mm_sec_ddr, size); 299 if (!mm_store) 300 goto bad; 301 area->store = phys_to_virt(tee_mm_get_smem(mm_store), 302 MEM_AREA_TA_RAM); 303 if (!area->store) 304 goto bad; 305 area->u.rwp = calloc(size / SMALL_PAGE_SIZE, 306 sizeof(struct pager_rw_pstate)); 307 if (!area->u.rwp) 308 goto bad; 309 at = AREA_TYPE_RW; 310 } else { 311 area->store = (void *)store; 312 area->u.hashes = hashes; 313 at = AREA_TYPE_RO; 314 } 315 out: 316 area->pgt = pgt; 317 area->base = base; 318 area->size = size; 319 area->flags = flags; 320 area->type = at; 321 return area; 322 bad: 323 tee_mm_free(mm_store); 324 free(area->u.rwp); 325 free(area); 326 return NULL; 327 } 328 329 static void area_insert_tail(struct tee_pager_area *area) 330 { 331 uint32_t exceptions = pager_lock(); 332 333 TAILQ_INSERT_TAIL(&tee_pager_area_head, area, link); 334 335 pager_unlock(exceptions); 336 } 337 KEEP_PAGER(area_insert_tail); 338 339 static size_t tbl_usage_count(struct pgt *pgt) 340 { 341 size_t n; 342 paddr_t pa; 343 size_t usage = 0; 344 345 for (n = 0; n < tee_pager_tbl_info.num_entries; n++) { 346 core_mmu_get_entry_primitive(pgt->tbl, tee_pager_tbl_info.level, 347 n, &pa, NULL); 348 if (pa) 349 usage++; 350 } 351 return usage; 352 } 353 354 bool tee_pager_add_core_area(vaddr_t base, size_t size, uint32_t flags, 355 const void *store, const void *hashes) 356 { 357 struct tee_pager_area *area; 358 size_t tbl_va_size; 359 struct core_mmu_table_info *ti = &tee_pager_tbl_info; 360 361 DMSG("0x%" PRIxPTR " - 0x%" PRIxPTR " : flags 0x%x, store %p, hashes %p", 362 base, base + size, flags, store, hashes); 363 364 if (base & SMALL_PAGE_MASK || size & SMALL_PAGE_MASK || !size) { 365 EMSG("invalid pager area [%" PRIxVA " +0x%zx]", base, size); 366 panic(); 367 } 368 369 if (!(flags & TEE_MATTR_PW) && (!store || !hashes)) 370 panic("write pages cannot provide store or hashes"); 371 372 if ((flags & TEE_MATTR_PW) && (store || hashes)) 373 panic("non-write pages must provide store and hashes"); 374 375 if (!pager_core_pgt.tbl) { 376 pager_core_pgt.tbl = ti->table; 377 pgt_set_used_entries(&pager_core_pgt, 378 tbl_usage_count(&pager_core_pgt)); 379 } 380 381 tbl_va_size = (1 << ti->shift) * ti->num_entries; 382 if (!core_is_buffer_inside(base, size, ti->va_base, tbl_va_size)) { 383 DMSG("area 0x%" PRIxPTR " len 0x%zx doesn't fit it translation table 0x%" PRIxVA " len 0x%zx", 384 base, size, ti->va_base, tbl_va_size); 385 return false; 386 } 387 388 area = alloc_area(&pager_core_pgt, base, size, flags, store, hashes); 389 if (!area) 390 return false; 391 392 area_insert_tail(area); 393 return true; 394 } 395 396 static struct tee_pager_area *find_area(struct tee_pager_area_head *areas, 397 vaddr_t va) 398 { 399 struct tee_pager_area *area; 400 401 if (!areas) 402 return NULL; 403 404 TAILQ_FOREACH(area, areas, link) { 405 if (core_is_buffer_inside(va, 1, area->base, area->size)) 406 return area; 407 } 408 return NULL; 409 } 410 411 #ifdef CFG_PAGED_USER_TA 412 static struct tee_pager_area *find_uta_area(vaddr_t va) 413 { 414 struct tee_ta_ctx *ctx = thread_get_tsd()->ctx; 415 416 if (!ctx || !is_user_ta_ctx(ctx)) 417 return NULL; 418 return find_area(to_user_ta_ctx(ctx)->areas, va); 419 } 420 #else 421 static struct tee_pager_area *find_uta_area(vaddr_t va __unused) 422 { 423 return NULL; 424 } 425 #endif /*CFG_PAGED_USER_TA*/ 426 427 428 static uint32_t get_area_mattr(uint32_t area_flags) 429 { 430 uint32_t attr = TEE_MATTR_VALID_BLOCK | TEE_MATTR_SECURE | 431 TEE_MATTR_CACHE_CACHED << TEE_MATTR_CACHE_SHIFT | 432 (area_flags & (TEE_MATTR_PRWX | TEE_MATTR_URWX)); 433 434 if (!(area_flags & (TEE_MATTR_UR | TEE_MATTR_UX | TEE_MATTR_UW))) 435 attr |= TEE_MATTR_GLOBAL; 436 437 return attr; 438 } 439 440 static paddr_t get_pmem_pa(struct tee_pager_pmem *pmem) 441 { 442 paddr_t pa; 443 unsigned idx; 444 445 idx = core_mmu_va2idx(&pager_alias_tbl_info, (vaddr_t)pmem->va_alias); 446 core_mmu_get_entry(&pager_alias_tbl_info, idx, &pa, NULL); 447 return pa; 448 } 449 450 static bool decrypt_page(struct pager_rw_pstate *rwp, const void *src, 451 void *dst) 452 { 453 struct pager_aes_gcm_iv iv = { 454 { (vaddr_t)rwp, rwp->iv >> 32, rwp->iv } 455 }; 456 457 return pager_aes_gcm_decrypt(pager_ae_key, sizeof(pager_ae_key), 458 &iv, rwp->tag, src, dst, SMALL_PAGE_SIZE); 459 } 460 461 static void encrypt_page(struct pager_rw_pstate *rwp, void *src, void *dst) 462 { 463 struct pager_aes_gcm_iv iv; 464 465 assert((rwp->iv + 1) > rwp->iv); 466 rwp->iv++; 467 /* 468 * IV is constructed as recommended in section "8.2.1 Deterministic 469 * Construction" of "Recommendation for Block Cipher Modes of 470 * Operation: Galois/Counter Mode (GCM) and GMAC", 471 * http://csrc.nist.gov/publications/nistpubs/800-38D/SP-800-38D.pdf 472 */ 473 iv.iv[0] = (vaddr_t)rwp; 474 iv.iv[1] = rwp->iv >> 32; 475 iv.iv[2] = rwp->iv; 476 477 if (!pager_aes_gcm_encrypt(pager_ae_key, sizeof(pager_ae_key), 478 &iv, rwp->tag, 479 src, dst, SMALL_PAGE_SIZE)) 480 panic("gcm failed"); 481 } 482 483 static void tee_pager_load_page(struct tee_pager_area *area, vaddr_t page_va, 484 void *va_alias) 485 { 486 size_t idx = (page_va - area->base) >> SMALL_PAGE_SHIFT; 487 const void *stored_page = area->store + idx * SMALL_PAGE_SIZE; 488 struct core_mmu_table_info *ti; 489 uint32_t attr_alias; 490 paddr_t pa_alias; 491 unsigned int idx_alias; 492 493 /* Insure we are allowed to write to aliased virtual page */ 494 ti = &pager_alias_tbl_info; 495 idx_alias = core_mmu_va2idx(ti, (vaddr_t)va_alias); 496 core_mmu_get_entry(ti, idx_alias, &pa_alias, &attr_alias); 497 if (!(attr_alias & TEE_MATTR_PW)) { 498 attr_alias |= TEE_MATTR_PW; 499 core_mmu_set_entry(ti, idx_alias, pa_alias, attr_alias); 500 tlbi_mva_allasid((vaddr_t)va_alias); 501 } 502 503 switch (area->type) { 504 case AREA_TYPE_RO: 505 { 506 const void *hash = area->u.hashes + 507 idx * TEE_SHA256_HASH_SIZE; 508 509 memcpy(va_alias, stored_page, SMALL_PAGE_SIZE); 510 incr_ro_hits(); 511 512 if (hash_sha256_check(hash, va_alias, 513 SMALL_PAGE_SIZE) != TEE_SUCCESS) { 514 EMSG("PH 0x%" PRIxVA " failed", page_va); 515 panic(); 516 } 517 } 518 /* Forbid write to aliases for read-only (maybe exec) pages */ 519 attr_alias &= ~TEE_MATTR_PW; 520 core_mmu_set_entry(ti, idx_alias, pa_alias, attr_alias); 521 tlbi_mva_allasid((vaddr_t)va_alias); 522 break; 523 case AREA_TYPE_RW: 524 FMSG("Restore %p %#" PRIxVA " iv %#" PRIx64, 525 va_alias, page_va, area->u.rwp[idx].iv); 526 if (!area->u.rwp[idx].iv) 527 memset(va_alias, 0, SMALL_PAGE_SIZE); 528 else if (!decrypt_page(&area->u.rwp[idx], stored_page, 529 va_alias)) { 530 EMSG("PH 0x%" PRIxVA " failed", page_va); 531 panic(); 532 } 533 incr_rw_hits(); 534 break; 535 case AREA_TYPE_LOCK: 536 FMSG("Zero init %p %#" PRIxVA, va_alias, page_va); 537 memset(va_alias, 0, SMALL_PAGE_SIZE); 538 break; 539 default: 540 panic(); 541 } 542 } 543 544 static void tee_pager_save_page(struct tee_pager_pmem *pmem, uint32_t attr) 545 { 546 const uint32_t dirty_bits = TEE_MATTR_PW | TEE_MATTR_UW | 547 TEE_MATTR_HIDDEN_DIRTY_BLOCK; 548 549 if (pmem->area->type == AREA_TYPE_RW && (attr & dirty_bits)) { 550 size_t offs = pmem->area->base & CORE_MMU_PGDIR_MASK; 551 size_t idx = pmem->pgidx - (offs >> SMALL_PAGE_SHIFT); 552 void *stored_page = pmem->area->store + idx * SMALL_PAGE_SIZE; 553 554 assert(pmem->area->flags & (TEE_MATTR_PW | TEE_MATTR_UW)); 555 encrypt_page(&pmem->area->u.rwp[idx], pmem->va_alias, 556 stored_page); 557 FMSG("Saved %#" PRIxVA " iv %#" PRIx64, 558 pmem->area->base + idx * SMALL_PAGE_SIZE, 559 pmem->area->u.rwp[idx].iv); 560 } 561 } 562 563 static void area_get_entry(struct tee_pager_area *area, size_t idx, 564 paddr_t *pa, uint32_t *attr) 565 { 566 assert(area->pgt); 567 assert(idx < tee_pager_tbl_info.num_entries); 568 core_mmu_get_entry_primitive(area->pgt->tbl, tee_pager_tbl_info.level, 569 idx, pa, attr); 570 } 571 572 static void area_set_entry(struct tee_pager_area *area, size_t idx, 573 paddr_t pa, uint32_t attr) 574 { 575 assert(area->pgt); 576 assert(idx < tee_pager_tbl_info.num_entries); 577 core_mmu_set_entry_primitive(area->pgt->tbl, tee_pager_tbl_info.level, 578 idx, pa, attr); 579 } 580 581 static size_t area_va2idx(struct tee_pager_area *area, vaddr_t va) 582 { 583 return (va - (area->base & ~CORE_MMU_PGDIR_MASK)) >> SMALL_PAGE_SHIFT; 584 } 585 586 static vaddr_t __maybe_unused area_idx2va(struct tee_pager_area *area, 587 size_t idx) 588 { 589 return (idx << SMALL_PAGE_SHIFT) + (area->base & ~CORE_MMU_PGDIR_MASK); 590 } 591 592 #ifdef CFG_PAGED_USER_TA 593 static void free_area(struct tee_pager_area *area) 594 { 595 tee_mm_free(tee_mm_find(&tee_mm_sec_ddr, 596 virt_to_phys(area->store))); 597 if (area->type == AREA_TYPE_RW) 598 free(area->u.rwp); 599 free(area); 600 } 601 602 static bool pager_add_uta_area(struct user_ta_ctx *utc, vaddr_t base, 603 size_t size) 604 { 605 struct tee_pager_area *area; 606 uint32_t flags; 607 vaddr_t b = base; 608 size_t s = ROUNDUP(size, SMALL_PAGE_SIZE); 609 610 if (!utc->areas) { 611 utc->areas = malloc(sizeof(*utc->areas)); 612 if (!utc->areas) 613 return false; 614 TAILQ_INIT(utc->areas); 615 } 616 617 flags = TEE_MATTR_PRW | TEE_MATTR_URWX; 618 619 while (s) { 620 size_t s2; 621 622 if (find_area(utc->areas, b)) 623 return false; 624 625 s2 = MIN(CORE_MMU_PGDIR_SIZE - (b & CORE_MMU_PGDIR_MASK), s); 626 627 /* Table info will be set when the context is activated. */ 628 area = alloc_area(NULL, b, s2, flags, NULL, NULL); 629 if (!area) 630 return false; 631 TAILQ_INSERT_TAIL(utc->areas, area, link); 632 b += s2; 633 s -= s2; 634 } 635 636 return true; 637 } 638 639 bool tee_pager_add_uta_area(struct user_ta_ctx *utc, vaddr_t base, size_t size) 640 { 641 struct thread_specific_data *tsd = thread_get_tsd(); 642 struct tee_pager_area *area; 643 struct core_mmu_table_info dir_info = { NULL }; 644 645 if (&utc->ctx != tsd->ctx) { 646 /* 647 * Changes are to an utc that isn't active. Just add the 648 * areas page tables will be dealt with later. 649 */ 650 return pager_add_uta_area(utc, base, size); 651 } 652 653 /* 654 * Assign page tables before adding areas to be able to tell which 655 * are newly added and should be removed in case of failure. 656 */ 657 tee_pager_assign_uta_tables(utc); 658 if (!pager_add_uta_area(utc, base, size)) { 659 struct tee_pager_area *next_a; 660 661 /* Remove all added areas */ 662 TAILQ_FOREACH_SAFE(area, utc->areas, link, next_a) { 663 if (!area->pgt) { 664 TAILQ_REMOVE(utc->areas, area, link); 665 free_area(area); 666 } 667 } 668 return false; 669 } 670 671 /* 672 * Assign page tables to the new areas and make sure that the page 673 * tables are registered in the upper table. 674 */ 675 tee_pager_assign_uta_tables(utc); 676 core_mmu_get_user_pgdir(&dir_info); 677 TAILQ_FOREACH(area, utc->areas, link) { 678 paddr_t pa; 679 size_t idx; 680 uint32_t attr; 681 682 idx = core_mmu_va2idx(&dir_info, area->pgt->vabase); 683 core_mmu_get_entry(&dir_info, idx, &pa, &attr); 684 685 /* 686 * Check if the page table already is used, if it is, it's 687 * already registered. 688 */ 689 if (area->pgt->num_used_entries) { 690 assert(attr & TEE_MATTR_TABLE); 691 assert(pa == virt_to_phys(area->pgt->tbl)); 692 continue; 693 } 694 695 attr = TEE_MATTR_SECURE | TEE_MATTR_TABLE; 696 pa = virt_to_phys(area->pgt->tbl); 697 assert(pa); 698 /* 699 * Note that the update of the table entry is guaranteed to 700 * be atomic. 701 */ 702 core_mmu_set_entry(&dir_info, idx, pa, attr); 703 } 704 705 return true; 706 } 707 708 static void init_tbl_info_from_pgt(struct core_mmu_table_info *ti, 709 struct pgt *pgt) 710 { 711 assert(pgt); 712 ti->table = pgt->tbl; 713 ti->va_base = pgt->vabase; 714 ti->level = tee_pager_tbl_info.level; 715 ti->shift = tee_pager_tbl_info.shift; 716 ti->num_entries = tee_pager_tbl_info.num_entries; 717 } 718 719 static void transpose_area(struct tee_pager_area *area, struct pgt *new_pgt, 720 vaddr_t new_base) 721 { 722 uint32_t exceptions = pager_lock(); 723 724 /* 725 * If there's no pgt assigned to the old area there's no pages to 726 * deal with either, just update with a new pgt and base. 727 */ 728 if (area->pgt) { 729 struct core_mmu_table_info old_ti; 730 struct core_mmu_table_info new_ti; 731 struct tee_pager_pmem *pmem; 732 733 init_tbl_info_from_pgt(&old_ti, area->pgt); 734 init_tbl_info_from_pgt(&new_ti, new_pgt); 735 736 737 TAILQ_FOREACH(pmem, &tee_pager_pmem_head, link) { 738 vaddr_t va; 739 paddr_t pa; 740 uint32_t attr; 741 742 if (pmem->area != area) 743 continue; 744 core_mmu_get_entry(&old_ti, pmem->pgidx, &pa, &attr); 745 core_mmu_set_entry(&old_ti, pmem->pgidx, 0, 0); 746 747 assert(pa == get_pmem_pa(pmem)); 748 assert(attr); 749 assert(area->pgt->num_used_entries); 750 area->pgt->num_used_entries--; 751 752 va = core_mmu_idx2va(&old_ti, pmem->pgidx); 753 va = va - area->base + new_base; 754 pmem->pgidx = core_mmu_va2idx(&new_ti, va); 755 core_mmu_set_entry(&new_ti, pmem->pgidx, pa, attr); 756 new_pgt->num_used_entries++; 757 } 758 } 759 760 area->pgt = new_pgt; 761 area->base = new_base; 762 pager_unlock(exceptions); 763 } 764 KEEP_PAGER(transpose_area); 765 766 void tee_pager_transfer_uta_region(struct user_ta_ctx *src_utc, 767 vaddr_t src_base, 768 struct user_ta_ctx *dst_utc, 769 vaddr_t dst_base, struct pgt **dst_pgt, 770 size_t size) 771 { 772 struct tee_pager_area *area; 773 struct tee_pager_area *next_a; 774 775 TAILQ_FOREACH_SAFE(area, src_utc->areas, link, next_a) { 776 vaddr_t new_area_base; 777 size_t new_idx; 778 779 if (!core_is_buffer_inside(area->base, area->size, 780 src_base, size)) 781 continue; 782 783 TAILQ_REMOVE(src_utc->areas, area, link); 784 785 new_area_base = dst_base + (src_base - area->base); 786 new_idx = (new_area_base - dst_pgt[0]->vabase) / 787 CORE_MMU_PGDIR_SIZE; 788 assert((new_area_base & ~CORE_MMU_PGDIR_MASK) == 789 dst_pgt[new_idx]->vabase); 790 transpose_area(area, dst_pgt[new_idx], new_area_base); 791 792 /* 793 * Assert that this will not cause any conflicts in the new 794 * utc. This should already be guaranteed, but a bug here 795 * could be tricky to find. 796 */ 797 assert(!find_area(dst_utc->areas, area->base)); 798 TAILQ_INSERT_TAIL(dst_utc->areas, area, link); 799 } 800 } 801 802 static void rem_area(struct tee_pager_area_head *area_head, 803 struct tee_pager_area *area) 804 { 805 struct tee_pager_pmem *pmem; 806 uint32_t exceptions; 807 808 exceptions = pager_lock(); 809 810 TAILQ_REMOVE(area_head, area, link); 811 812 TAILQ_FOREACH(pmem, &tee_pager_pmem_head, link) { 813 if (pmem->area == area) { 814 area_set_entry(area, pmem->pgidx, 0, 0); 815 tlbi_mva_allasid(area_idx2va(area, pmem->pgidx)); 816 pgt_dec_used_entries(area->pgt); 817 pmem->area = NULL; 818 pmem->pgidx = INVALID_PGIDX; 819 } 820 } 821 822 pager_unlock(exceptions); 823 free_area(area); 824 } 825 KEEP_PAGER(rem_area); 826 827 void tee_pager_rem_uta_region(struct user_ta_ctx *utc, vaddr_t base, 828 size_t size) 829 { 830 struct tee_pager_area *area; 831 struct tee_pager_area *next_a; 832 size_t s = ROUNDUP(size, SMALL_PAGE_SIZE); 833 834 TAILQ_FOREACH_SAFE(area, utc->areas, link, next_a) { 835 if (core_is_buffer_inside(area->base, area->size, base, s)) 836 rem_area(utc->areas, area); 837 } 838 } 839 840 void tee_pager_rem_uta_areas(struct user_ta_ctx *utc) 841 { 842 struct tee_pager_area *area; 843 844 if (!utc->areas) 845 return; 846 847 while (true) { 848 area = TAILQ_FIRST(utc->areas); 849 if (!area) 850 break; 851 TAILQ_REMOVE(utc->areas, area, link); 852 free_area(area); 853 } 854 855 free(utc->areas); 856 } 857 858 bool tee_pager_set_uta_area_attr(struct user_ta_ctx *utc, vaddr_t base, 859 size_t size, uint32_t flags) 860 { 861 bool ret; 862 vaddr_t b = base; 863 size_t s = size; 864 size_t s2; 865 struct tee_pager_area *area = find_area(utc->areas, b); 866 uint32_t exceptions; 867 struct tee_pager_pmem *pmem; 868 paddr_t pa; 869 uint32_t a; 870 uint32_t f; 871 872 f = (flags & TEE_MATTR_URWX) | TEE_MATTR_UR | TEE_MATTR_PR; 873 if (f & TEE_MATTR_UW) 874 f |= TEE_MATTR_PW; 875 f = get_area_mattr(f); 876 877 exceptions = pager_lock(); 878 879 while (s) { 880 s2 = MIN(CORE_MMU_PGDIR_SIZE - (b & CORE_MMU_PGDIR_MASK), s); 881 if (!area || area->base != b || area->size != s2) { 882 ret = false; 883 goto out; 884 } 885 b += s2; 886 s -= s2; 887 888 TAILQ_FOREACH(pmem, &tee_pager_pmem_head, link) { 889 if (pmem->area != area) 890 continue; 891 area_get_entry(pmem->area, pmem->pgidx, &pa, &a); 892 if (a & TEE_MATTR_VALID_BLOCK) 893 assert(pa == get_pmem_pa(pmem)); 894 else 895 pa = get_pmem_pa(pmem); 896 if (a == f) 897 continue; 898 area_set_entry(pmem->area, pmem->pgidx, 0, 0); 899 tlbi_mva_allasid(area_idx2va(pmem->area, pmem->pgidx)); 900 if (!(flags & TEE_MATTR_UW)) 901 tee_pager_save_page(pmem, a); 902 903 area_set_entry(pmem->area, pmem->pgidx, pa, f); 904 /* 905 * Make sure the table update is visible before 906 * continuing. 907 */ 908 dsb_ishst(); 909 910 if (flags & TEE_MATTR_UX) { 911 void *va = (void *)area_idx2va(pmem->area, 912 pmem->pgidx); 913 914 cache_op_inner(DCACHE_AREA_CLEAN, va, 915 SMALL_PAGE_SIZE); 916 cache_op_inner(ICACHE_AREA_INVALIDATE, va, 917 SMALL_PAGE_SIZE); 918 } 919 } 920 921 area->flags = f; 922 area = TAILQ_NEXT(area, link); 923 } 924 925 ret = true; 926 out: 927 pager_unlock(exceptions); 928 return ret; 929 } 930 KEEP_PAGER(tee_pager_set_uta_area_attr); 931 #endif /*CFG_PAGED_USER_TA*/ 932 933 static bool tee_pager_unhide_page(vaddr_t page_va) 934 { 935 struct tee_pager_pmem *pmem; 936 937 TAILQ_FOREACH(pmem, &tee_pager_pmem_head, link) { 938 paddr_t pa; 939 uint32_t attr; 940 941 if (pmem->pgidx == INVALID_PGIDX) 942 continue; 943 944 area_get_entry(pmem->area, pmem->pgidx, &pa, &attr); 945 946 if (!(attr & 947 (TEE_MATTR_HIDDEN_BLOCK | TEE_MATTR_HIDDEN_DIRTY_BLOCK))) 948 continue; 949 950 if (area_va2idx(pmem->area, page_va) == pmem->pgidx) { 951 uint32_t a = get_area_mattr(pmem->area->flags); 952 953 /* page is hidden, show and move to back */ 954 if (pa != get_pmem_pa(pmem)) 955 panic("unexpected pa"); 956 957 /* 958 * If it's not a dirty block, then it should be 959 * read only. 960 */ 961 if (!(attr & TEE_MATTR_HIDDEN_DIRTY_BLOCK)) 962 a &= ~(TEE_MATTR_PW | TEE_MATTR_UW); 963 else 964 FMSG("Unhide %#" PRIxVA, page_va); 965 966 if (page_va == 0x8000a000) 967 FMSG("unhide %#" PRIxVA " a %#" PRIX32, 968 page_va, a); 969 area_set_entry(pmem->area, pmem->pgidx, pa, a); 970 971 TAILQ_REMOVE(&tee_pager_pmem_head, pmem, link); 972 TAILQ_INSERT_TAIL(&tee_pager_pmem_head, pmem, link); 973 974 tlbi_mva_allasid(page_va); 975 976 incr_hidden_hits(); 977 return true; 978 } 979 } 980 981 return false; 982 } 983 984 static void tee_pager_hide_pages(void) 985 { 986 struct tee_pager_pmem *pmem; 987 size_t n = 0; 988 989 TAILQ_FOREACH(pmem, &tee_pager_pmem_head, link) { 990 paddr_t pa; 991 uint32_t attr; 992 uint32_t a; 993 994 if (n >= TEE_PAGER_NHIDE) 995 break; 996 n++; 997 998 /* we cannot hide pages when pmem->area is not defined. */ 999 if (!pmem->area) 1000 continue; 1001 1002 area_get_entry(pmem->area, pmem->pgidx, &pa, &attr); 1003 if (!(attr & TEE_MATTR_VALID_BLOCK)) 1004 continue; 1005 1006 assert(pa == get_pmem_pa(pmem)); 1007 if (attr & (TEE_MATTR_PW | TEE_MATTR_UW)){ 1008 a = TEE_MATTR_HIDDEN_DIRTY_BLOCK; 1009 FMSG("Hide %#" PRIxVA, 1010 area_idx2va(pmem->area, pmem->pgidx)); 1011 } else 1012 a = TEE_MATTR_HIDDEN_BLOCK; 1013 1014 area_set_entry(pmem->area, pmem->pgidx, pa, a); 1015 tlbi_mva_allasid(area_idx2va(pmem->area, pmem->pgidx)); 1016 } 1017 } 1018 1019 /* 1020 * Find mapped pmem, hide and move to pageble pmem. 1021 * Return false if page was not mapped, and true if page was mapped. 1022 */ 1023 static bool tee_pager_release_one_phys(struct tee_pager_area *area, 1024 vaddr_t page_va) 1025 { 1026 struct tee_pager_pmem *pmem; 1027 unsigned pgidx; 1028 paddr_t pa; 1029 uint32_t attr; 1030 1031 pgidx = area_va2idx(area, page_va); 1032 area_get_entry(area, pgidx, &pa, &attr); 1033 1034 FMSG("%" PRIxVA " : %" PRIxPA "|%x", page_va, pa, attr); 1035 1036 TAILQ_FOREACH(pmem, &tee_pager_lock_pmem_head, link) { 1037 if (pmem->area != area || pmem->pgidx != pgidx) 1038 continue; 1039 1040 assert(pa == get_pmem_pa(pmem)); 1041 area_set_entry(area, pgidx, 0, 0); 1042 pgt_dec_used_entries(area->pgt); 1043 TAILQ_REMOVE(&tee_pager_lock_pmem_head, pmem, link); 1044 pmem->area = NULL; 1045 pmem->pgidx = INVALID_PGIDX; 1046 tee_pager_npages++; 1047 set_npages(); 1048 TAILQ_INSERT_HEAD(&tee_pager_pmem_head, pmem, link); 1049 incr_zi_released(); 1050 return true; 1051 } 1052 1053 return false; 1054 } 1055 1056 /* Finds the oldest page and unmats it from its old virtual address */ 1057 static struct tee_pager_pmem *tee_pager_get_page(struct tee_pager_area *area) 1058 { 1059 struct tee_pager_pmem *pmem; 1060 1061 pmem = TAILQ_FIRST(&tee_pager_pmem_head); 1062 if (!pmem) { 1063 EMSG("No pmem entries"); 1064 return NULL; 1065 } 1066 if (pmem->pgidx != INVALID_PGIDX) { 1067 uint32_t a; 1068 1069 assert(pmem->area && pmem->area->pgt); 1070 area_get_entry(pmem->area, pmem->pgidx, NULL, &a); 1071 area_set_entry(pmem->area, pmem->pgidx, 0, 0); 1072 pgt_dec_used_entries(pmem->area->pgt); 1073 tlbi_mva_allasid(area_idx2va(pmem->area, pmem->pgidx)); 1074 tee_pager_save_page(pmem, a); 1075 } 1076 1077 TAILQ_REMOVE(&tee_pager_pmem_head, pmem, link); 1078 pmem->pgidx = INVALID_PGIDX; 1079 pmem->area = NULL; 1080 if (area->type == AREA_TYPE_LOCK) { 1081 /* Move page to lock list */ 1082 if (tee_pager_npages <= 0) 1083 panic("running out of page"); 1084 tee_pager_npages--; 1085 set_npages(); 1086 TAILQ_INSERT_TAIL(&tee_pager_lock_pmem_head, pmem, link); 1087 } else { 1088 /* move page to back */ 1089 TAILQ_INSERT_TAIL(&tee_pager_pmem_head, pmem, link); 1090 } 1091 1092 return pmem; 1093 } 1094 1095 static bool pager_update_permissions(struct tee_pager_area *area, 1096 struct abort_info *ai, bool *handled) 1097 { 1098 unsigned int pgidx = area_va2idx(area, ai->va); 1099 uint32_t attr; 1100 paddr_t pa; 1101 1102 *handled = false; 1103 1104 area_get_entry(area, pgidx, &pa, &attr); 1105 1106 /* Not mapped */ 1107 if (!(attr & TEE_MATTR_VALID_BLOCK)) 1108 return false; 1109 1110 /* Not readable, should not happen */ 1111 if (abort_is_user_exception(ai)) { 1112 if (!(attr & TEE_MATTR_UR)) 1113 return true; 1114 } else { 1115 if (!(attr & TEE_MATTR_PR)) { 1116 abort_print_error(ai); 1117 panic(); 1118 } 1119 } 1120 1121 switch (core_mmu_get_fault_type(ai->fault_descr)) { 1122 case CORE_MMU_FAULT_TRANSLATION: 1123 case CORE_MMU_FAULT_READ_PERMISSION: 1124 if (ai->abort_type == ABORT_TYPE_PREFETCH) { 1125 /* Check attempting to execute from an NOX page */ 1126 if (abort_is_user_exception(ai)) { 1127 if (!(attr & TEE_MATTR_UX)) 1128 return true; 1129 } else { 1130 if (!(attr & TEE_MATTR_PX)) { 1131 abort_print_error(ai); 1132 panic(); 1133 } 1134 } 1135 } 1136 /* Since the page is mapped now it's OK */ 1137 break; 1138 case CORE_MMU_FAULT_WRITE_PERMISSION: 1139 /* Check attempting to write to an RO page */ 1140 if (abort_is_user_exception(ai)) { 1141 if (!(area->flags & TEE_MATTR_UW)) 1142 return true; 1143 if (!(attr & TEE_MATTR_UW)) { 1144 FMSG("Dirty %p", 1145 (void *)(ai->va & ~SMALL_PAGE_MASK)); 1146 area_set_entry(area, pgidx, pa, 1147 get_area_mattr(area->flags)); 1148 tlbi_mva_allasid(ai->va & ~SMALL_PAGE_MASK); 1149 } 1150 1151 } else { 1152 if (!(area->flags & TEE_MATTR_PW)) { 1153 abort_print_error(ai); 1154 panic(); 1155 } 1156 if (!(attr & TEE_MATTR_PW)) { 1157 FMSG("Dirty %p", 1158 (void *)(ai->va & ~SMALL_PAGE_MASK)); 1159 area_set_entry(area, pgidx, pa, 1160 get_area_mattr(area->flags)); 1161 tlbi_mva_allasid(ai->va & ~SMALL_PAGE_MASK); 1162 } 1163 } 1164 /* Since permissions has been updated now it's OK */ 1165 break; 1166 default: 1167 /* Some fault we can't deal with */ 1168 if (abort_is_user_exception(ai)) 1169 return true; 1170 abort_print_error(ai); 1171 panic(); 1172 } 1173 *handled = true; 1174 return true; 1175 } 1176 1177 #ifdef CFG_TEE_CORE_DEBUG 1178 static void stat_handle_fault(void) 1179 { 1180 static size_t num_faults; 1181 static size_t min_npages = SIZE_MAX; 1182 static size_t total_min_npages = SIZE_MAX; 1183 1184 num_faults++; 1185 if ((num_faults % 1024) == 0 || tee_pager_npages < total_min_npages) { 1186 DMSG("nfaults %zu npages %zu (min %zu)", 1187 num_faults, tee_pager_npages, min_npages); 1188 min_npages = tee_pager_npages; /* reset */ 1189 } 1190 if (tee_pager_npages < min_npages) 1191 min_npages = tee_pager_npages; 1192 if (tee_pager_npages < total_min_npages) 1193 total_min_npages = tee_pager_npages; 1194 } 1195 #else 1196 static void stat_handle_fault(void) 1197 { 1198 } 1199 #endif 1200 1201 bool tee_pager_handle_fault(struct abort_info *ai) 1202 { 1203 struct tee_pager_area *area; 1204 vaddr_t page_va = ai->va & ~SMALL_PAGE_MASK; 1205 uint32_t exceptions; 1206 bool ret; 1207 1208 #ifdef TEE_PAGER_DEBUG_PRINT 1209 abort_print(ai); 1210 #endif 1211 1212 /* 1213 * We're updating pages that can affect several active CPUs at a 1214 * time below. We end up here because a thread tries to access some 1215 * memory that isn't available. We have to be careful when making 1216 * that memory available as other threads may succeed in accessing 1217 * that address the moment after we've made it available. 1218 * 1219 * That means that we can't just map the memory and populate the 1220 * page, instead we use the aliased mapping to populate the page 1221 * and once everything is ready we map it. 1222 */ 1223 exceptions = pager_lock(); 1224 1225 stat_handle_fault(); 1226 1227 /* check if the access is valid */ 1228 if (abort_is_user_exception(ai)) { 1229 area = find_uta_area(ai->va); 1230 1231 } else { 1232 area = find_area(&tee_pager_area_head, ai->va); 1233 if (!area) 1234 area = find_uta_area(ai->va); 1235 } 1236 if (!area || !area->pgt) { 1237 ret = false; 1238 goto out; 1239 } 1240 1241 if (!tee_pager_unhide_page(page_va)) { 1242 struct tee_pager_pmem *pmem = NULL; 1243 uint32_t attr; 1244 1245 /* 1246 * The page wasn't hidden, but some other core may have 1247 * updated the table entry before we got here or we need 1248 * to make a read-only page read-write (dirty). 1249 */ 1250 if (pager_update_permissions(area, ai, &ret)) { 1251 /* 1252 * Nothing more to do with the abort. The problem 1253 * could already have been dealt with from another 1254 * core or if ret is false the TA will be paniced. 1255 */ 1256 goto out; 1257 } 1258 1259 pmem = tee_pager_get_page(area); 1260 if (!pmem) { 1261 abort_print(ai); 1262 panic(); 1263 } 1264 1265 /* load page code & data */ 1266 tee_pager_load_page(area, page_va, pmem->va_alias); 1267 1268 /* 1269 * We've updated the page using the aliased mapping and 1270 * some cache maintenence is now needed if it's an 1271 * executable page. 1272 * 1273 * Since the d-cache is a Physically-indexed, 1274 * physically-tagged (PIPT) cache we can clean the aliased 1275 * address instead of the real virtual address. 1276 * 1277 * The i-cache can also be PIPT, but may be something else 1278 * to, to keep it simple we invalidate the entire i-cache. 1279 * As a future optimization we may invalidate only the 1280 * aliased area if it a PIPT cache else the entire cache. 1281 */ 1282 if (area->flags & (TEE_MATTR_PX | TEE_MATTR_UX)) { 1283 /* 1284 * Doing these operations to LoUIS (Level of 1285 * unification, Inner Shareable) would be enough 1286 */ 1287 cache_op_inner(DCACHE_AREA_CLEAN, pmem->va_alias, 1288 SMALL_PAGE_SIZE); 1289 cache_op_inner(ICACHE_INVALIDATE, NULL, 0); 1290 } 1291 1292 pmem->area = area; 1293 pmem->pgidx = area_va2idx(area, ai->va); 1294 attr = get_area_mattr(area->flags) & 1295 ~(TEE_MATTR_PW | TEE_MATTR_UW); 1296 area_set_entry(area, pmem->pgidx, get_pmem_pa(pmem), attr); 1297 /* No need to flush TLB for this entry, it was invalid */ 1298 pgt_inc_used_entries(area->pgt); 1299 1300 FMSG("Mapped 0x%" PRIxVA " -> 0x%" PRIxPA, 1301 area_idx2va(area, pmem->pgidx), get_pmem_pa(pmem)); 1302 1303 } 1304 1305 tee_pager_hide_pages(); 1306 ret = true; 1307 out: 1308 pager_unlock(exceptions); 1309 return ret; 1310 } 1311 1312 void tee_pager_add_pages(vaddr_t vaddr, size_t npages, bool unmap) 1313 { 1314 struct core_mmu_table_info *ti = &tee_pager_tbl_info; 1315 size_t n; 1316 1317 DMSG("0x%" PRIxVA " - 0x%" PRIxVA " : %d", 1318 vaddr, vaddr + npages * SMALL_PAGE_SIZE, (int)unmap); 1319 1320 /* setup memory */ 1321 for (n = 0; n < npages; n++) { 1322 struct tee_pager_pmem *pmem; 1323 vaddr_t va = vaddr + n * SMALL_PAGE_SIZE; 1324 unsigned pgidx = core_mmu_va2idx(ti, va); 1325 paddr_t pa; 1326 uint32_t attr; 1327 1328 /* 1329 * Note that we can only support adding pages in the 1330 * valid range of this table info, currently not a problem. 1331 */ 1332 core_mmu_get_entry(ti, pgidx, &pa, &attr); 1333 1334 /* Ignore unmapped pages/blocks */ 1335 if (!(attr & TEE_MATTR_VALID_BLOCK)) 1336 continue; 1337 1338 pmem = malloc(sizeof(struct tee_pager_pmem)); 1339 if (!pmem) 1340 panic("out of mem"); 1341 1342 pmem->va_alias = pager_add_alias_page(pa); 1343 1344 if (unmap) { 1345 pmem->area = NULL; 1346 pmem->pgidx = INVALID_PGIDX; 1347 core_mmu_set_entry(ti, pgidx, 0, 0); 1348 pgt_dec_used_entries(&pager_core_pgt); 1349 } else { 1350 /* 1351 * The page is still mapped, let's assign the area 1352 * and update the protection bits accordingly. 1353 */ 1354 pmem->area = find_area(&tee_pager_area_head, va); 1355 assert(pmem->area->pgt == &pager_core_pgt); 1356 pmem->pgidx = pgidx; 1357 assert(pa == get_pmem_pa(pmem)); 1358 area_set_entry(pmem->area, pgidx, pa, 1359 get_area_mattr(pmem->area->flags)); 1360 } 1361 1362 tee_pager_npages++; 1363 incr_npages_all(); 1364 set_npages(); 1365 TAILQ_INSERT_TAIL(&tee_pager_pmem_head, pmem, link); 1366 } 1367 1368 /* 1369 * As this is done at inits, invalidate all TLBs once instead of 1370 * targeting only the modified entries. 1371 */ 1372 tlbi_all(); 1373 } 1374 1375 #ifdef CFG_PAGED_USER_TA 1376 static struct pgt *find_pgt(struct pgt *pgt, vaddr_t va) 1377 { 1378 struct pgt *p = pgt; 1379 1380 while (p && (va & ~CORE_MMU_PGDIR_MASK) != p->vabase) 1381 p = SLIST_NEXT(p, link); 1382 return p; 1383 } 1384 1385 void tee_pager_assign_uta_tables(struct user_ta_ctx *utc) 1386 { 1387 struct tee_pager_area *area; 1388 struct pgt *pgt = SLIST_FIRST(&thread_get_tsd()->pgt_cache); 1389 1390 TAILQ_FOREACH(area, utc->areas, link) { 1391 if (!area->pgt) 1392 area->pgt = find_pgt(pgt, area->base); 1393 else 1394 assert(area->pgt == find_pgt(pgt, area->base)); 1395 if (!area->pgt) 1396 panic(); 1397 } 1398 } 1399 1400 static void pager_save_and_release_entry(struct tee_pager_pmem *pmem) 1401 { 1402 uint32_t attr; 1403 1404 assert(pmem->area && pmem->area->pgt); 1405 1406 area_get_entry(pmem->area, pmem->pgidx, NULL, &attr); 1407 area_set_entry(pmem->area, pmem->pgidx, 0, 0); 1408 tlbi_mva_allasid(area_idx2va(pmem->area, pmem->pgidx)); 1409 tee_pager_save_page(pmem, attr); 1410 assert(pmem->area->pgt->num_used_entries); 1411 pmem->area->pgt->num_used_entries--; 1412 pmem->pgidx = INVALID_PGIDX; 1413 pmem->area = NULL; 1414 } 1415 1416 void tee_pager_pgt_save_and_release_entries(struct pgt *pgt) 1417 { 1418 struct tee_pager_pmem *pmem; 1419 struct tee_pager_area *area; 1420 uint32_t exceptions = pager_lock(); 1421 1422 if (!pgt->num_used_entries) 1423 goto out; 1424 1425 TAILQ_FOREACH(pmem, &tee_pager_pmem_head, link) { 1426 if (!pmem->area || pmem->pgidx == INVALID_PGIDX) 1427 continue; 1428 if (pmem->area->pgt == pgt) 1429 pager_save_and_release_entry(pmem); 1430 } 1431 assert(!pgt->num_used_entries); 1432 1433 out: 1434 if (is_user_ta_ctx(pgt->ctx)) { 1435 TAILQ_FOREACH(area, to_user_ta_ctx(pgt->ctx)->areas, link) { 1436 if (area->pgt == pgt) 1437 area->pgt = NULL; 1438 } 1439 } 1440 1441 pager_unlock(exceptions); 1442 } 1443 KEEP_PAGER(tee_pager_pgt_save_and_release_entries); 1444 #endif /*CFG_PAGED_USER_TA*/ 1445 1446 void tee_pager_release_phys(void *addr, size_t size) 1447 { 1448 bool unmaped = false; 1449 vaddr_t va = (vaddr_t)addr; 1450 vaddr_t begin = ROUNDUP(va, SMALL_PAGE_SIZE); 1451 vaddr_t end = ROUNDDOWN(va + size, SMALL_PAGE_SIZE); 1452 struct tee_pager_area *area; 1453 uint32_t exceptions; 1454 1455 if (end <= begin) 1456 return; 1457 1458 area = find_area(&tee_pager_area_head, begin); 1459 if (!area || 1460 area != find_area(&tee_pager_area_head, end - SMALL_PAGE_SIZE)) 1461 panic(); 1462 1463 exceptions = pager_lock(); 1464 1465 for (va = begin; va < end; va += SMALL_PAGE_SIZE) 1466 unmaped |= tee_pager_release_one_phys(area, va); 1467 1468 if (unmaped) 1469 tlbi_mva_range(begin, end - begin, SMALL_PAGE_SIZE); 1470 1471 pager_unlock(exceptions); 1472 } 1473 KEEP_PAGER(tee_pager_release_phys); 1474 1475 void *tee_pager_alloc(size_t size, uint32_t flags) 1476 { 1477 tee_mm_entry_t *mm; 1478 uint32_t f = TEE_MATTR_PW | TEE_MATTR_PR | (flags & TEE_MATTR_LOCKED); 1479 1480 if (!size) 1481 return NULL; 1482 1483 mm = tee_mm_alloc(&tee_mm_vcore, ROUNDUP(size, SMALL_PAGE_SIZE)); 1484 if (!mm) 1485 return NULL; 1486 1487 tee_pager_add_core_area(tee_mm_get_smem(mm), tee_mm_get_bytes(mm), 1488 f, NULL, NULL); 1489 1490 return (void *)tee_mm_get_smem(mm); 1491 } 1492