smol-gilbraltar/kernel/translation_table.c
2024-12-23 23:44:47 +01:00

93 lines
2.8 KiB
C

#include <log.h>
#include <mem.h>
#include <pager.h>
#include <string.h>
#include <sysconfig.h>
#include <translation_table.h>
#define LEVEL2_TABLE_ENTRIES 256
static union TARMV8MMU_LEVEL2_DESCRIPTOR *l2_table;
static size_t mem = 0;
extern uint8_t _etext;
static union TARMV8MMU_LEVEL3_DESCRIPTOR *
new_level_l3_table(uintptr_t base_addr) {
union TARMV8MMU_LEVEL3_DESCRIPTOR *l3_table =
(union TARMV8MMU_LEVEL3_DESCRIPTOR *)gilbraltar_palloc();
for (unsigned page = 0; page < ARMV8MMU_TABLE_ENTRIES; page++) {
struct TARMV8MMU_LEVEL3_PAGE_DESCRIPTOR *desc = &l3_table[page].page;
desc->value11 = 3;
desc->attr_indx = ATTR_INDX_NORMAL;
desc->ns = 0;
desc->ap = ATTR_IB_AP_RW_EL1;
desc->sh = ATTR_IB_SH_INNER_SHAREABLE;
desc->af = 1;
desc->ng = 0;
desc->reserved0_1 = 0;
desc->output_addr = ARMV8MMUL3PAGEADDR(base_addr);
desc->reserved0_2 = 0;
desc->continuous = 0;
desc->pxn = 0;
desc->uxn = 1;
desc->ignored = 0;
if (base_addr >= (uint64_t)&_etext) {
desc->pxn = 1;
if ((base_addr >= mem && base_addr < GIGABYTE) ||
base_addr > (8 * GIGABYTE - 1)) {
desc->attr_indx = ATTR_INDX_DEVICE;
desc->sh = ATTR_IB_SH_OUTER_SHAREABLE;
} else if (base_addr >= MEM_COHERENT_REGION &&
base_addr < MEM_HEAP_START) {
desc->attr_indx = ATTR_INDX_COHERENT;
desc->sh = ATTR_IB_SH_OUTER_SHAREABLE;
}
}
base_addr += ARMV8MMU_LEVEL3_PAGE_SIZE;
}
return (l3_table);
}
uintptr_t gilbraltar_translation_table_base(void) {
return ((uintptr_t)l2_table);
}
void gilbraltar_translation_table_init(size_t size) {
l2_table = (union TARMV8MMU_LEVEL2_DESCRIPTOR *)gilbraltar_palloc();
gilbraltar_log(DEBUG, "L2 table allocated.\r\n");
memset(l2_table, 0, PAGE_SIZE);
for (unsigned entry = 0; entry < LEVEL2_TABLE_ENTRIES; entry++) {
uint64_t base_addr =
(uint64_t)entry * ARMV8MMU_TABLE_ENTRIES * ARMV8MMU_LEVEL3_PAGE_SIZE;
if (base_addr >= 8 * GIGABYTE &&
!(MEM_IOMEM_AXI_START <= base_addr && base_addr <= MEM_IOMEM_AXI_END) &&
!(MEM_IOMEM_SOC_START <= base_addr && base_addr <= MEM_IOMEM_SOC_END) &&
!(MEM_IOMEM_PCIE_START <= base_addr && base_addr <= MEM_IOMEM_PCIE_END))
continue; // as far as we can
gilbraltar_log(DEBUG, "New L3 table.\r\n");
union TARMV8MMU_LEVEL3_DESCRIPTOR *l3_table = new_level_l3_table(base_addr);
struct TARMV8MMU_LEVEL2_TABLE_DESCRIPTOR *desc = &l2_table[entry].table;
desc->value11 = 3;
desc->ignored1 = 0;
desc->table_addr = ARMV8MMUL2TABLEADDR((uint64_t)l3_table);
desc->reserved0 = 0;
desc->ignored2 = 0;
desc->pxn_table = 0;
desc->uxn_table = 0;
desc->ap_table = AP_TABLE_ALL_ACCESS;
desc->ns_table = 0;
}
data_sync_barrier();
}