mirror of
https://github.com/CTCaer/switch-l4t-atf.git
synced 2024-12-04 08:53:37 +00:00
xlat: Introduce API to get memory attributes of a region
This patch introduces a new API in the translation tables library (v2), that allows to query the memory attributes of a memory block or a memory page. Change-Id: I45a8b39a53da39e7617cbac4bff5658dc1b20a11 Co-authored-by: Sandrine Bailleux <sandrine.bailleux@arm.com> Co-authored-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com> Signed-off-by: Antonio Nino Diaz <antonio.ninodiaz@arm.com>
This commit is contained in:
parent
8bf5bac88e
commit
1be910bb3d
@ -24,9 +24,19 @@
|
||||
#define FOUR_KB_INDEX(x) ((x) >> FOUR_KB_SHIFT)
|
||||
|
||||
#define INVALID_DESC U(0x0)
|
||||
/*
|
||||
* A block descriptor points to a region of memory bigger than the granule size
|
||||
* (e.g. a 2MB region when the granule size is 4KB).
|
||||
*/
|
||||
#define BLOCK_DESC U(0x1) /* Table levels 0-2 */
|
||||
/* A table descriptor points to the next level of translation table. */
|
||||
#define TABLE_DESC U(0x3) /* Table levels 0-2 */
|
||||
/*
|
||||
* A page descriptor points to a page, i.e. a memory region whose size is the
|
||||
* translation granule size (e.g. 4KB).
|
||||
*/
|
||||
#define PAGE_DESC U(0x3) /* Table level 3 */
|
||||
|
||||
#define DESC_MASK U(0x3)
|
||||
|
||||
#define FIRST_LEVEL_DESC_N ONE_GB_SHIFT
|
||||
@ -84,10 +94,22 @@
|
||||
#define XLAT_BLOCK_MASK(level) (XLAT_BLOCK_SIZE(level) - 1)
|
||||
/* Mask to get the address bits common to a block of a certain table level*/
|
||||
#define XLAT_ADDR_MASK(level) (~XLAT_BLOCK_MASK(level))
|
||||
/*
|
||||
* Extract from the given virtual address the index into the given lookup level.
|
||||
* This macro assumes the system is using the 4KB translation granule.
|
||||
*/
|
||||
#define XLAT_TABLE_IDX(virtual_addr, level) \
|
||||
(((virtual_addr) >> XLAT_ADDR_SHIFT(level)) & ULL(0x1FF))
|
||||
|
||||
/*
|
||||
* AP[1] bit is ignored by hardware and is
|
||||
* treated as if it is One in EL2/EL3
|
||||
* The ARMv8 translation table descriptor format defines AP[2:1] as the Access
|
||||
* Permissions bits, and does not define an AP[0] bit.
|
||||
*
|
||||
* AP[1] is valid only for a stage 1 translation that supports two VA ranges
|
||||
* (i.e. in the ARMv8A.0 architecture, that is the S-EL1&0 regime).
|
||||
*
|
||||
* AP[1] is RES0 for stage 1 translations that support only one VA range
|
||||
* (e.g. EL3).
|
||||
*/
|
||||
#define AP2_SHIFT U(0x7)
|
||||
#define AP2_RO U(0x1)
|
||||
@ -121,6 +143,28 @@
|
||||
#define ATTR_INDEX_MASK U(0x3)
|
||||
#define ATTR_INDEX_GET(attr) (((attr) >> 2) & ATTR_INDEX_MASK)
|
||||
|
||||
/*
|
||||
* Shift values for the attributes fields in a block or page descriptor.
|
||||
* See section D4.3.3 in the ARMv8-A ARM (issue B.a).
|
||||
*/
|
||||
|
||||
/* Memory attributes index field, AttrIndx[2:0]. */
|
||||
#define ATTR_INDEX_SHIFT 2
|
||||
/* Non-secure bit, NS. */
|
||||
#define NS_SHIFT 5
|
||||
/* Shareability field, SH[1:0] */
|
||||
#define SHAREABILITY_SHIFT 8
|
||||
/* The Access Flag, AF. */
|
||||
#define ACCESS_FLAG_SHIFT 10
|
||||
/* The not global bit, nG. */
|
||||
#define NOT_GLOBAL_SHIFT 11
|
||||
/* Contiguous hint bit. */
|
||||
#define CONT_HINT_SHIFT 52
|
||||
/* Execute-never bits, XN. */
|
||||
#define PXN_SHIFT 53
|
||||
#define XN_SHIFT 54
|
||||
#define UXN_SHIFT XN_SHIFT
|
||||
|
||||
/*
|
||||
* Flags to override default values used to program system registers while
|
||||
* enabling the MMU.
|
||||
|
@ -251,5 +251,23 @@ int mmap_remove_dynamic_region_ctx(xlat_ctx_t *ctx,
|
||||
|
||||
#endif /* PLAT_XLAT_TABLES_DYNAMIC */
|
||||
|
||||
/*
|
||||
* Query the memory attributes of a memory page in a set of translation tables.
|
||||
*
|
||||
* Return 0 on success, a negative error code on error.
|
||||
* On success, the attributes are stored into *attributes.
|
||||
*
|
||||
* ctx
|
||||
* Translation context to work on.
|
||||
* base_va
|
||||
* Virtual address of the page to get the attributes of.
|
||||
* There are no alignment restrictions on this address. The attributes of the
|
||||
* memory page it lies within are returned.
|
||||
* attributes
|
||||
* Output parameter where to store the attributes of the targeted memory page.
|
||||
*/
|
||||
int get_mem_attributes(const xlat_ctx_t *ctx, uintptr_t base_va,
|
||||
mmap_attr_t *attributes);
|
||||
|
||||
#endif /*__ASSEMBLY__*/
|
||||
#endif /* __XLAT_TABLES_V2_H__ */
|
||||
|
@ -1022,7 +1022,7 @@ int mmap_remove_dynamic_region(uintptr_t base_va, size_t size)
|
||||
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
||||
|
||||
/* Print the attributes of the specified block descriptor. */
|
||||
static void xlat_desc_print(xlat_ctx_t *ctx, uint64_t desc)
|
||||
static void xlat_desc_print(const xlat_ctx_t *ctx, uint64_t desc)
|
||||
{
|
||||
int mem_type_index = ATTR_INDEX_GET(desc);
|
||||
xlat_regime_t xlat_regime = ctx->xlat_regime;
|
||||
@ -1315,3 +1315,195 @@ void enable_mmu_el3(unsigned int flags)
|
||||
}
|
||||
|
||||
#endif /* AARCH32 */
|
||||
|
||||
/*
|
||||
* Do a translation table walk to find the block or page descriptor that maps
|
||||
* virtual_addr.
|
||||
*
|
||||
* On success, return the address of the descriptor within the translation
|
||||
* table. Its lookup level is stored in '*out_level'.
|
||||
* On error, return NULL.
|
||||
*
|
||||
* xlat_table_base
|
||||
* Base address for the initial lookup level.
|
||||
* xlat_table_base_entries
|
||||
* Number of entries in the translation table for the initial lookup level.
|
||||
* virt_addr_space_size
|
||||
* Size in bytes of the virtual address space.
|
||||
*/
|
||||
static uint64_t *find_xlat_table_entry(uintptr_t virtual_addr,
|
||||
void *xlat_table_base,
|
||||
int xlat_table_base_entries,
|
||||
unsigned long long virt_addr_space_size,
|
||||
int *out_level)
|
||||
{
|
||||
unsigned int start_level;
|
||||
uint64_t *table;
|
||||
int entries;
|
||||
|
||||
VERBOSE("%s(%p)\n", __func__, (void *)virtual_addr);
|
||||
|
||||
start_level = GET_XLAT_TABLE_LEVEL_BASE(virt_addr_space_size);
|
||||
VERBOSE("Starting translation table walk from level %i\n", start_level);
|
||||
|
||||
table = xlat_table_base;
|
||||
entries = xlat_table_base_entries;
|
||||
|
||||
for (unsigned int level = start_level;
|
||||
level <= XLAT_TABLE_LEVEL_MAX;
|
||||
++level) {
|
||||
int idx;
|
||||
uint64_t desc;
|
||||
uint64_t desc_type;
|
||||
|
||||
VERBOSE("Table address: %p\n", (void *)table);
|
||||
|
||||
idx = XLAT_TABLE_IDX(virtual_addr, level);
|
||||
VERBOSE("Index into level %i table: %i\n", level, idx);
|
||||
if (idx >= entries) {
|
||||
VERBOSE("Invalid address\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
desc = table[idx];
|
||||
desc_type = desc & DESC_MASK;
|
||||
VERBOSE("Descriptor at level %i: 0x%llx\n", level,
|
||||
(unsigned long long)desc);
|
||||
|
||||
if (desc_type == INVALID_DESC) {
|
||||
VERBOSE("Invalid entry (memory not mapped)\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (level == XLAT_TABLE_LEVEL_MAX) {
|
||||
/*
|
||||
* There can't be table entries at the final lookup
|
||||
* level.
|
||||
*/
|
||||
assert(desc_type == PAGE_DESC);
|
||||
VERBOSE("Descriptor mapping a memory page (size: 0x%llx)\n",
|
||||
(unsigned long long)XLAT_BLOCK_SIZE(XLAT_TABLE_LEVEL_MAX));
|
||||
*out_level = level;
|
||||
return &table[idx];
|
||||
}
|
||||
|
||||
if (desc_type == BLOCK_DESC) {
|
||||
VERBOSE("Descriptor mapping a memory block (size: 0x%llx)\n",
|
||||
(unsigned long long)XLAT_BLOCK_SIZE(level));
|
||||
*out_level = level;
|
||||
return &table[idx];
|
||||
}
|
||||
|
||||
assert(desc_type == TABLE_DESC);
|
||||
VERBOSE("Table descriptor, continuing xlat table walk...\n");
|
||||
table = (uint64_t *)(uintptr_t)(desc & TABLE_ADDR_MASK);
|
||||
entries = XLAT_TABLE_ENTRIES;
|
||||
}
|
||||
|
||||
/*
|
||||
* This shouldn't be reached, the translation table walk should end at
|
||||
* most at level XLAT_TABLE_LEVEL_MAX and return from inside the loop.
|
||||
*/
|
||||
assert(0);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int get_mem_attributes_internal(const xlat_ctx_t *ctx, uintptr_t base_va,
|
||||
mmap_attr_t *attributes, uint64_t **table_entry,
|
||||
unsigned long long *addr_pa, int *table_level)
|
||||
{
|
||||
uint64_t *entry;
|
||||
uint64_t desc;
|
||||
int level;
|
||||
unsigned long long virt_addr_space_size;
|
||||
|
||||
/*
|
||||
* Sanity-check arguments.
|
||||
*/
|
||||
assert(ctx != NULL);
|
||||
assert(ctx->initialized);
|
||||
assert(ctx->xlat_regime == EL1_EL0_REGIME || ctx->xlat_regime == EL3_REGIME);
|
||||
|
||||
virt_addr_space_size = (unsigned long long)ctx->va_max_address + 1;
|
||||
assert(virt_addr_space_size > 0);
|
||||
|
||||
entry = find_xlat_table_entry(base_va,
|
||||
ctx->base_table,
|
||||
ctx->base_table_entries,
|
||||
virt_addr_space_size,
|
||||
&level);
|
||||
if (entry == NULL) {
|
||||
WARN("Address %p is not mapped.\n", (void *)base_va);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (addr_pa != NULL) {
|
||||
*addr_pa = *entry & TABLE_ADDR_MASK;
|
||||
}
|
||||
|
||||
if (table_entry != NULL) {
|
||||
*table_entry = entry;
|
||||
}
|
||||
|
||||
if (table_level != NULL) {
|
||||
*table_level = level;
|
||||
}
|
||||
|
||||
desc = *entry;
|
||||
|
||||
#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
|
||||
VERBOSE("Attributes: ");
|
||||
xlat_desc_print(ctx, desc);
|
||||
tf_printf("\n");
|
||||
#endif /* LOG_LEVEL >= LOG_LEVEL_VERBOSE */
|
||||
|
||||
assert(attributes != NULL);
|
||||
*attributes = 0;
|
||||
|
||||
int attr_index = (desc >> ATTR_INDEX_SHIFT) & ATTR_INDEX_MASK;
|
||||
|
||||
if (attr_index == ATTR_IWBWA_OWBWA_NTR_INDEX) {
|
||||
*attributes |= MT_MEMORY;
|
||||
} else if (attr_index == ATTR_NON_CACHEABLE_INDEX) {
|
||||
*attributes |= MT_NON_CACHEABLE;
|
||||
} else {
|
||||
assert(attr_index == ATTR_DEVICE_INDEX);
|
||||
*attributes |= MT_DEVICE;
|
||||
}
|
||||
|
||||
int ap2_bit = (desc >> AP2_SHIFT) & 1;
|
||||
|
||||
if (ap2_bit == AP2_RW)
|
||||
*attributes |= MT_RW;
|
||||
|
||||
if (ctx->xlat_regime == EL1_EL0_REGIME) {
|
||||
int ap1_bit = (desc >> AP1_SHIFT) & 1;
|
||||
if (ap1_bit == AP1_ACCESS_UNPRIVILEGED)
|
||||
*attributes |= MT_USER;
|
||||
}
|
||||
|
||||
int ns_bit = (desc >> NS_SHIFT) & 1;
|
||||
|
||||
if (ns_bit == 1)
|
||||
*attributes |= MT_NS;
|
||||
|
||||
uint64_t xn_mask = xlat_arch_regime_get_xn_desc(ctx->xlat_regime);
|
||||
|
||||
if ((desc & xn_mask) == xn_mask) {
|
||||
*attributes |= MT_EXECUTE_NEVER;
|
||||
} else {
|
||||
assert((desc & xn_mask) == 0);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int get_mem_attributes(const xlat_ctx_t *ctx, uintptr_t base_va,
|
||||
mmap_attr_t *attributes)
|
||||
{
|
||||
return get_mem_attributes_internal(ctx, base_va, attributes,
|
||||
NULL, NULL, NULL);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user