aboutsummaryrefslogtreecommitdiff
path: root/arm/common_mmu.c
diff options
context:
space:
mode:
Diffstat (limited to 'arm/common_mmu.c')
-rw-r--r--arm/common_mmu.c128
1 files changed, 128 insertions, 0 deletions
diff --git a/arm/common_mmu.c b/arm/common_mmu.c
new file mode 100644
index 0000000..cf9fc15
--- /dev/null
+++ b/arm/common_mmu.c
@@ -0,0 +1,128 @@
+#include "common_svc.h"
+#include "common_mmu.h"
+#include "common_defs.h"
+
+void pagetable_add_section_entries(uint32_t *ttbr, pagetable_map_entry_t *pe)
+{
+ uint32_t va = pe->va;
+ uint32_t pa = pe->pa;
+ uint32_t len = pe->len;
+ uint32_t l1idx = va >> L1_INDEX_SHIFT;
+ uint32_t l1attr = SECTION;
+ uint32_t size = SECTION_SIZE;
+
+ l1attr |= IS_SET(pe, NONSECURE) ? SECTION_NS : 0;
+ l1attr |= IS_SET(pe, P0_R)
+ ? IS_SET(pe, P0_W) ? SECTION_P0_RW : SECTION_P0_RO
+ : SECTION_P0_NONE;
+ l1attr |= IS_SET(pe, P1_R)
+ ? IS_SET(pe, P1_W) ? SECTION_P1_RW : SECTION_P1_RO
+ : SECTION_P1_NONE;
+ l1attr |= IS_SET(pe, P0_X) ? 0 : SECTION_XN;
+ l1attr |= IS_SET(pe, P1_X) ? 0 : SECTION_PXN;
+ l1attr |= IS_SET(pe, NOTGLOBAL) ? (SECTION_NG) : 0;
+ l1attr |= IS_SET(pe, DEVICE)
+ ? IS_SET(pe, SHARED)
+ ? SECTION_DEVICE_SHAREABLE : SECTION_DEVICE_UNSHAREABLE
+ : IS_SET(pe, SHARED) ? (SECTION_S) : 0;
+ l1attr |= IS_SET(pe, WT_CACHED)
+ ? SECTION_WT_CACHED : IS_SET(pe, WB_CACHED)
+ ? SECTION_WB_CACHED
+ : IS_SET(pe, WBA_CACHED)
+ ? SECTION_WBA_CACHED : SECTION_UNCACHED;
+
+ /* Round up to the next segment increment */
+ len = (len + (SECTION_SIZE-1)) & ~(SECTION_SIZE-1);
+
+ for (; len > 0; va += size, pa += size, len -= size) {
+ l1idx = L1_INDEX(va);
+ ttbr[l1idx] = (pa & SECTION_PA_MASK) | l1attr;
+ DEBUG_MSG("Mapped L1 0x%x to 0x%x (%p (0x%x) = 0x%x)\n",
+ va, pa, &ttbr[l1idx], l1idx, ttbr[l1idx]);
+ }
+}
+
+void pagetable_add_page_entries(uint32_t *ttbr, pagetable_map_entry_t *pe)
+{
+ uint32_t va = pe->va;
+ uint32_t pa = pe->pa;
+ uint32_t len = pe->len;
+ uint32_t l2len = 0;;
+ uint32_t *l2base = ttbr + BYTE_TO_INT(L1_TABLE_SIZE);
+ uint32_t *l2addr;
+ uint32_t size = PAGE_SIZE(PAGE);
+ uint32_t l1attr = L1_TYPE_PAGE, l2attr = L2_TYPE(pe->type);
+ uint32_t l1idx, l2idx;
+
+ l1attr |= IS_SET(pe, NONSECURE) ? PAGE_NS : 0;
+ l1attr |= IS_SET(pe, P1_X) ? 0 : PAGE_PXN;
+
+ l2attr |= IS_SET(pe, P0_R)
+ ? IS_SET(pe, P0_W) ? PAGE_P0_RW : PAGE_P0_RO
+ : PAGE_P0_NONE;
+ l2attr |= IS_SET(pe, P1_R)
+ ? IS_SET(pe, P1_W) ? PAGE_P1_RW : PAGE_P1_RO
+ : PAGE_P1_NONE;
+ l2attr |= IS_SET(pe, P0_X) ? 0 : PAGE_XN(PAGE_SMALL);
+ l2attr |= IS_SET(pe, NOTGLOBAL) ? (PAGE_NG) : 0;
+ l2attr |= IS_SET(pe, DEVICE)
+ ? IS_SET(pe, SHARED)
+ ? PAGE_DEVICE_SHAREABLE
+ : PAGE_DEVICE_UNSHAREABLE(PAGE_SMALL)
+ : IS_SET(pe, SHARED) ? (PAGE_S) : 0;
+ l2attr |= IS_SET(pe, WT_CACHED)
+ ? PAGE_WT_CACHED
+ : IS_SET(pe, WB_CACHED)
+ ? PAGE_WB_CACHED
+ : IS_SET(pe, WBA_CACHED)
+ ? PAGE_WBA_CACHED(PAGE_SMALL)
+ : PAGE_UNCACHED(PAGE_SMALL);
+
+ /* Round up to the next page increment */
+ len = (len + (PAGE_SIZE(PAGE)-1)) & ~(PAGE_SIZE(PAGE)-1);
+
+ while (len > 0) {
+ l1idx = L1_INDEX(va);
+ l2addr = l2base + BYTE_TO_INT(L2_TABLE_SIZE * l1idx);
+ ttbr[l1idx] = (uint32_t)l2addr | l1attr;
+
+ DEBUG_MSG("Added L1 0x%x to 0x%x (ttbrn[%x] = %x)\n",
+ va, l2addr, l1idx, ttbr[l1idx]);
+
+ /* Set the level 2 page table size to the smaller of the total
+ * remaining length or the remaining length in the 1MB section.
+ */
+ l2len = L1_MAP_SIZE - (va & (L1_MAP_SIZE - 1));
+ l2len = (l2len > len) ? len : l2len;
+
+ for (; l2len > 0; va += size, pa += size, l2len -= size, len -= size) {
+ l2idx = L2_INDEX(va);
+ l2addr[l2idx] = (pa & PAGE_PA_MASK) | l2attr;
+ DEBUG_MSG("Mapped L2 0x%x to 0x%x (%p (0x%x) = 0x%x)\n",
+ va, pa, &l2addr[l2idx], l2idx, l2addr[l2idx]);
+ }
+ }
+}
+
+void pagetable_add_entries(uint32_t *ttbr, pagetable_map_entry_t *entries,
+ uint32_t count)
+{
+ uint32_t i;
+
+ for (i = 0; i < count; i++) {
+ if (entries[i].type == SECTION) {
+ pagetable_add_section_entries(ttbr, &entries[i]);
+ } else if (entries[i].type == PAGE || entries[i].type == LARGE_PAGE) {
+ pagetable_add_page_entries(ttbr, &entries[i]);
+ }
+ }
+}
+
+void pagetable_init(uint32_t *ttbr)
+{
+ int i;
+
+ for (i = 0; i < BYTE_TO_INT(L1_TABLE_SIZE); i++) {
+ ttbr[i] = 0;
+ }
+}