lib/xlat_tables_v2/xlat_tables_core.c
/*
 * Recursive function that writes to the translation tables and unmaps the
 * specified region.
 */
Recursive function that writes to the translation tables and unmaps the
specified region.
Recursive function that writes to the translation tables and unmaps the specified region .
static void xlat_tables_unmap_region(xlat_ctx_t *ctx, mmap_region_t *mm,
				     const uintptr_t table_base_va,
				     uint64_t *const table_base,
				     const unsigned int table_entries,
				     const unsigned int level)
{
	assert((level >= ctx->base_level) && (level <= XLAT_TABLE_LEVEL_MAX));
	uint64_t *subtable;
	uint64_t desc;
	uintptr_t table_idx_va;
	uintptr_t table_idx_end_va; 
	uintptr_t region_end_va = mm->base_va + mm->size - 1U;
	unsigned int table_idx;
	if (mm->base_va > table_base_va) {
		table_idx_va = mm->base_va & ~XLAT_BLOCK_MASK(level);
		table_idx = (unsigned int)((table_idx_va - table_base_va) >>
			    XLAT_ADDR_SHIFT(level));
		assert(table_idx < table_entries);
	} else {
		table_idx_va = table_base_va;
		table_idx = 0;
	}
	while (table_idx < table_entries) {
		table_idx_end_va = table_idx_va + XLAT_BLOCK_SIZE(level) - 1U;
		desc = table_base[table_idx];
		uint64_t desc_type = desc & DESC_MASK;
		action_t action;
		if ((mm->base_va <= table_idx_va) &&
		    (region_end_va >= table_idx_end_va)) {
			if (level == 3U) {
				assert(desc_type == PAGE_DESC);
				action = ACTION_WRITE_BLOCK_ENTRY;
			} else {
				if (desc_type == TABLE_DESC) {
					action = ACTION_RECURSE_INTO_TABLE;
				} else {
					assert(desc_type == BLOCK_DESC);
					action = ACTION_WRITE_BLOCK_ENTRY;
				}
			}
		} else if ((mm->base_va <= table_idx_end_va) ||
			   (region_end_va >= table_idx_va)) {
			assert(level < 3U);
			assert(desc_type == TABLE_DESC);
			action = ACTION_RECURSE_INTO_TABLE;
		} else {
			action = ACTION_NONE;
		}
		if (action == ACTION_WRITE_BLOCK_ENTRY) {
			table_base[table_idx] = INVALID_DESC;
			xlat_arch_tlbi_va(table_idx_va, ctx->xlat_regime);
		} else if (action == ACTION_RECURSE_INTO_TABLE) {
			subtable = (uint64_t *)(uintptr_t)(desc & TABLE_ADDR_MASK);
			xlat_tables_unmap_region(ctx, mm, table_idx_va,
						 subtable, XLAT_TABLE_ENTRIES,
						 level + 1U);
			if (xlat_table_is_empty(ctx, subtable) != 0) {
				table_base[table_idx] = INVALID_DESC;
				xlat_arch_tlbi_va(table_idx_va,
						  ctx->xlat_regime);
			}
		} else {
			assert(action == ACTION_NONE);
		}
		table_idx++;
		table_idx_va += XLAT_BLOCK_SIZE(level);
		if (region_end_va <= table_idx_va)
			break;
	}
	if (level > ctx->base_level)
		xlat_table_dec_regions_count(ctx, table_base);
}
static void xlat_tables_unmap_region ( xlat_ctx_t * ctx , mmap_region_t * mm , const uintptr_t table_base_va , uint64_t * const table_base , const unsigned int table_entries , const unsigned int level ) { assert ( ( level >= ctx -> base_level ) && ( level <= XLAT_TABLE_LEVEL_MAX ) ) ; uint64_t * subtable ; uint64_t desc ; uintptr_t table_idx_va ; uintptr_t table_idx_end_va ; uintptr_t region_end_va = mm -> base_va + mm -> size - 1U ; unsigned int table_idx ; if ( mm -> base_va > table_base_va ) { table_idx_va = mm -> base_va & ~ XLAT_BLOCK_MASK ( level ) ; table_idx = ( unsigned int ) ( ( table_idx_va - table_base_va ) >> XLAT_ADDR_SHIFT ( level ) ) ; assert ( table_idx < table_entries ) ; } else { table_idx_va = table_base_va ; table_idx = 0 ; } while ( table_idx < table_entries ) { table_idx_end_va = table_idx_va + XLAT_BLOCK_SIZE ( level ) - 1U ; desc = table_base [ table_idx ] ; uint64_t desc_type = desc & DESC_MASK ; action_t action ; if ( ( mm -> base_va <= table_idx_va ) && ( region_end_va >= table_idx_end_va ) ) { if ( level == 3U ) { assert ( desc_type == PAGE_DESC ) ; action = ACTION_WRITE_BLOCK_ENTRY ; } else { if ( desc_type == TABLE_DESC ) { action = ACTION_RECURSE_INTO_TABLE ; } else { assert ( desc_type == BLOCK_DESC ) ; action = ACTION_WRITE_BLOCK_ENTRY ; } } } else if ( ( mm -> base_va <= table_idx_end_va ) || ( region_end_va >= table_idx_va ) ) { assert ( level < 3U ) ; assert ( desc_type == TABLE_DESC ) ; action = ACTION_RECURSE_INTO_TABLE ; } else { action = ACTION_NONE ; } if ( action == ACTION_WRITE_BLOCK_ENTRY ) { table_base [ table_idx ] = INVALID_DESC ; xlat_arch_tlbi_va ( table_idx_va , ctx -> xlat_regime ) ; } else if ( action == ACTION_RECURSE_INTO_TABLE ) { subtable = ( uint64_t * ) ( uintptr_t ) ( desc & TABLE_ADDR_MASK ) ; xlat_tables_unmap_region ( ctx , mm , table_idx_va , subtable , XLAT_TABLE_ENTRIES , level + 1U ) ; if ( xlat_table_is_empty ( ctx , subtable ) != 0 ) { table_base [ table_idx ] = INVALID_DESC ; xlat_arch_tlbi_va ( table_idx_va , ctx -> xlat_regime ) ; } } else { assert ( action == ACTION_NONE ) ; } table_idx ++ ; table_idx_va += XLAT_BLOCK_SIZE ( level ) ; if ( region_end_va <= table_idx_va ) break ; } if ( level > ctx -> base_level ) xlat_table_dec_regions_count ( ctx , table_base ) ; }
Recursive function that writes to the translation tables and unmaps the
 specified region.
Recursive function that writes to the translation tables and unmaps the specified region .
/* End VA of this entry */ /* Find the first index of the table affected by the region. */ /* Start from the beginning of the table. */ /* Region covers all block */ /*
				 * Last level, only page descriptors allowed,
				 * erase it.
				 */ /*
				 * Other levels can have table descriptors. If
				 * so, recurse into it and erase descriptors
				 * inside it as needed. If there is a block
				 * descriptor, just erase it. If an invalid
				 * descriptor is found, this table isn't
				 * actually mapped, which shouldn't happen.
				 */ /*
			 * Region partially covers block.
			 *
			 * It can't happen in level 3.
			 *
			 * There must be a table descriptor here, if not there
			 * was a problem when mapping the region.
			 */ /* The region doesn't cover the block at all */ /* Recurse to write into subtable */ /*
			 * If the subtable is now empty, remove its reference.
			 */ /* If reached the end of the region, exit */