refactor(mm): replace max level with root level
The name `mm_max_level()` is misleading, since it is not actually the
maximum value that the level can be (since the root level is the "max"
level plus 1).
The use of `mm_max_level()` in `mm.c` was also inconsistent: sometimes
they call `mm_max_level() + 1` to calculate the root level, sometimes
they just pass `mm_max_level()` to recursive subcalls to process the
next level down. This made it hard to know when a plus or minus one was
needed and so ended up introducing off-by-one errors. Now, you always
start at `mm_root_level()` and pass `root_level - 1` to recursive
subcalls.
Also add explanatory comments explaining the level-related arithmetic.
Change-Id: I7b701d6d2c908db03c2853a008565126890e7959
Signed-off-by: Karl Meakin <karl.meakin@arm.com>
diff --git a/src/mm.c b/src/mm.c
index 9b2c006..078b3f0 100644
--- a/src/mm.c
+++ b/src/mm.c
@@ -79,19 +79,27 @@
/**
* Calculates the size of the address space represented by a page table entry at
- * the given level.
+ * the given level. See also Arm ARM, table D8-15
+ * - `level == 4`: 256 TiB (1 << 48)
+ * - `level == 3`: 512 GiB (1 << 39)
+ * - `level == 2`: 1 GiB (1 << 30)
+ * - `level == 1`: 2 MiB (1 << 21)
+ * - `level == 0`: 4 KiB (1 << 12)
*/
static size_t mm_entry_size(mm_level_t level)
{
+ assert(level <= 4);
return UINT64_C(1) << (PAGE_BITS + level * PAGE_LEVEL_BITS);
}
/**
- * Gets the address of the start of the next block of the given level.
+ * Get the start address of the range mapped by the next block of the given
+ * level.
*/
static ptable_addr_t mm_start_of_next_block(ptable_addr_t addr,
mm_level_t level)
{
+ assert(level <= 4);
return align_up(addr + 1, mm_entry_size(level));
}
@@ -108,7 +116,12 @@
/**
* For a given address, calculates the index at which its entry is stored in a
- * table at the given level.
+ * table at the given level. See also Arm ARM, table D8-14
+ * - `level == 4`: bits[51:48]
+ * - `level == 3`: bits[47:39]
+ * - `level == 2`: bits[38:30]
+ * - `level == 1`: bits[29:21]
+ * - `level == 0`: bits[20:12]
*/
static size_t mm_index(ptable_addr_t addr, mm_level_t level)
{
@@ -131,12 +144,12 @@
}
/**
- * Returns the maximum level in the page table given the flags.
+ * Returns the root level in the page table given the flags.
*/
-static mm_level_t mm_max_level(struct mm_flags flags)
+static mm_level_t mm_root_level(struct mm_flags flags)
{
- return flags.stage1 ? arch_mm_stage1_max_level()
- : arch_mm_stage2_max_level();
+ return flags.stage1 ? arch_mm_stage1_root_level()
+ : arch_mm_stage2_root_level();
}
/**
@@ -193,8 +206,7 @@
*/
ptable_addr_t mm_ptable_addr_space_end(struct mm_flags flags)
{
- return mm_root_table_count(flags) *
- mm_entry_size(mm_max_level(flags) + 1);
+ return mm_root_table_count(flags) * mm_entry_size(mm_root_level(flags));
}
/**
@@ -205,6 +217,7 @@
{
struct mm_page_table *tables;
uint8_t root_table_count = mm_root_table_count(flags);
+ mm_level_t root_level = mm_root_level(flags);
tables = mm_alloc_page_tables(root_table_count, ppool);
if (tables == NULL) {
@@ -214,7 +227,7 @@
for (size_t i = 0; i < root_table_count; i++) {
for (size_t j = 0; j < MM_PTE_PER_PAGE; j++) {
tables[i].entries[j] =
- arch_mm_absent_pte(mm_max_level(flags));
+ arch_mm_absent_pte(root_level - 1);
}
}
@@ -234,12 +247,13 @@
struct mm_flags flags, struct mpool *ppool)
{
struct mm_page_table *tables = mm_page_table_from_pa(ptable->root);
- mm_level_t level = mm_max_level(flags);
+ mm_level_t root_level = mm_root_level(flags);
uint8_t root_table_count = mm_root_table_count(flags);
for (size_t i = 0; i < root_table_count; ++i) {
for (size_t j = 0; j < MM_PTE_PER_PAGE; ++j) {
- mm_free_page_pte(tables[i].entries[j], level, ppool);
+ mm_free_page_pte(tables[i].entries[j], root_level - 1,
+ ppool);
}
}
@@ -432,7 +446,7 @@
paddr_t pa_end, mm_attr_t attrs,
struct mm_flags flags, struct mpool *ppool)
{
- mm_level_t root_level = mm_max_level(flags) + 1;
+ mm_level_t root_level = mm_root_level(flags);
ptable_addr_t ptable_end = mm_ptable_addr_space_end(flags);
ptable_addr_t end = mm_round_up_to_page(pa_addr(pa_end));
ptable_addr_t begin = mm_round_down_to_page(pa_addr(pa_begin));
@@ -440,10 +454,11 @@
ptable->root)[mm_index(begin, root_level)];
/*
- * Assert condition to communicate the API constraint of mm_max_level(),
- * that isn't encoded in the types, to the static analyzer.
+ * Assert condition to communicate the API constraint of
+ * mm_root_level(), that isn't encoded in the types, to the static
+ * analyzer.
*/
- assert(root_level >= 2);
+ assert(root_level >= 3);
/* Cap end to stay within the bounds of the page table. */
if (end > ptable_end) {
@@ -636,7 +651,7 @@
struct mm_flags flags)
{
struct mm_page_table *root_tables = mm_page_table_from_pa(ptable->root);
- mm_level_t root_level = mm_max_level(flags) + 1;
+ mm_level_t root_level = mm_root_level(flags);
uint8_t root_table_count = mm_root_table_count(flags);
uint32_t indent = 0;
@@ -792,7 +807,7 @@
bool non_secure, struct mpool *ppool)
{
struct mm_page_table *tables = mm_page_table_from_pa(ptable->root);
- mm_level_t level = mm_max_level(flags);
+ mm_level_t root_level = mm_root_level(flags);
uint8_t root_table_count = mm_root_table_count(flags);
ptable_addr_t block_addr = 0;
@@ -802,10 +817,11 @@
*/
for (size_t i = 0; i < root_table_count; ++i) {
for (size_t j = 0; j < MM_PTE_PER_PAGE; ++j) {
- mm_ptable_defrag_entry(ptable, block_addr,
- &(tables[i].entries[j]), level,
- flags, non_secure, ppool);
- block_addr = mm_start_of_next_block(block_addr, level);
+ mm_ptable_defrag_entry(
+ ptable, block_addr, &(tables[i].entries[j]),
+ root_level - 1, flags, non_secure, ppool);
+ block_addr = mm_start_of_next_block(block_addr,
+ root_level - 1);
}
}
@@ -877,8 +893,7 @@
ptable_addr_t end, mm_attr_t *attrs,
struct mm_flags flags)
{
- mm_level_t max_level = mm_max_level(flags);
- mm_level_t root_level = max_level + 1;
+ mm_level_t root_level = mm_root_level(flags);
ptable_addr_t ptable_end = mm_ptable_addr_space_end(flags);
struct mm_page_table *table;
bool got_attrs = false;
@@ -894,8 +909,9 @@
table = &mm_page_table_from_pa(
ptable->root)[mm_index(begin, root_level)];
while (begin < end) {
- if (!mm_ptable_get_attrs_level(table, begin, end, max_level,
- got_attrs, attrs)) {
+ if (!mm_ptable_get_attrs_level(table, begin, end,
+ root_level - 1, got_attrs,
+ attrs)) {
return false;
}