static mmap_region_t *init_xlation_table(mmap_region_t *mm, unsigned long base_va, unsigned long *table, unsigned level) { unsigned level_size_shift = L1_XLAT_ADDRESS_SHIFT - (level - 1) * XLAT_TABLE_ENTRIES_SHIFT; unsigned level_size = 1 << level_size_shift; unsigned long level_index_mask = XLAT_TABLE_ENTRIES_MASK << level_size_shift; assert(level <= 3); debug_print("New xlat table:\n"); do { unsigned long desc = UNSET_DESC; if (mm->base_va + mm->size <= base_va) { /* Area now after the region so skip it */ ++mm; continue; } debug_print(" %010lx %8lx " + 6 - 2 * level, base_va, level_size); if (mm->base_va >= base_va + level_size) { /* Next region is after area so nothing to map yet */ desc = INVALID_DESC; } else if (mm->base_va <= base_va && mm->base_va + mm->size >= base_va + level_size) { /* Next region covers all of area */ int attr = mmap_region_attr(mm, base_va, level_size); if (attr >= 0) desc = mmap_desc(attr, base_va - mm->base_va + mm->base_pa, level); } /* else Next region only partially covers area, so need */ if (desc == UNSET_DESC) { /* Area not covered by a region so need finer table */ unsigned long *new_table = xlat_tables[next_xlat++]; assert(next_xlat <= MAX_XLAT_TABLES); desc = TABLE_DESC | (unsigned long)new_table; /* Recurse to fill in new table */ mm = init_xlation_table(mm, base_va, new_table, level+1); } debug_print("\n"); *table++ = desc; base_va += level_size; } while (mm->size && (base_va & level_index_mask)); return mm; }
static struct tee_mmap_region *init_xlation_table(struct tee_mmap_region *mm, uint64_t base_va, uint64_t *table, unsigned level) { unsigned level_size_shift = L1_XLAT_ADDRESS_SHIFT - (level - 1) * XLAT_TABLE_ENTRIES_SHIFT; unsigned level_size = 1 << level_size_shift; uint64_t level_index_mask = XLAT_TABLE_ENTRIES_MASK << level_size_shift; assert(level <= 3); debug_print("New xlat table (level %u):", level); do { uint64_t desc = UNSET_DESC; if (mm->va + mm->size <= base_va) { /* Area now after the region so skip it */ mm++; continue; } if (mm->va >= base_va + level_size) { /* Next region is after area so nothing to map yet */ desc = INVALID_DESC; debug_print("%*s%010" PRIx64 " %8x", level * 2, "", base_va, level_size); } else if (mm->va <= base_va && mm->va + mm->size >= base_va + level_size) { /* Next region covers all of area */ int attr = mmap_region_attr(mm, base_va, level_size); if (attr >= 0) { desc = mmap_desc(attr, base_va - mm->va + mm->pa, level); debug_print("%*s%010" PRIx64 " %8x %s-%s-%s-%s", level * 2, "", base_va, level_size, attr & (TEE_MATTR_CACHE_CACHED << TEE_MATTR_CACHE_SHIFT) ? "MEM" : "DEV", attr & TEE_MATTR_PW ? "RW" : "RO", attr & TEE_MATTR_PX ? "X" : "XN", attr & TEE_MATTR_SECURE ? "S" : "NS"); } else { debug_print("%*s%010" PRIx64 " %8x", level * 2, "", base_va, level_size); } } /* else Next region only partially covers area, so need */ if (desc == UNSET_DESC) { /* Area not covered by a region so need finer table */ uint64_t *new_table = xlat_tables[next_xlat++]; /* Clear table before use */ memset(new_table, 0, XLAT_TABLE_SIZE); assert(next_xlat <= MAX_XLAT_TABLES); desc = TABLE_DESC | (uint64_t)(uintptr_t)new_table; /* Recurse to fill in new table */ mm = init_xlation_table(mm, base_va, new_table, level + 1); } *table++ = desc; base_va += level_size; } while (mm->size && (base_va & level_index_mask)); return mm; }