/* Copyright (C) 2012, Aaron Lindsay This file is part of Aedrix. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include #include #include #define SCTLR 15,0,1,0,0 #define TTBR0 15,0,2,0,0 #define TTBR1 15,0,2,0,1 #define TTBCR 15,0,2,0,2 #define _cp_read(var, cp, opc1, CRn, CRm, opc2) asm("mrc p" #cp ", " #opc1 ", %0, c" #CRn ", c" #CRm ", " #opc2 ";" : "=r"(var) : ) #define _cp_write(var, cp, opc1, CRn, CRm, opc2) asm("mcr p" #cp ", " #opc1 ", %0, c" #CRn ", c" #CRm ", " #opc2 ";" : : "r"(var) ) #define cp_read(var, ...) _cp_read(var, __VA_ARGS__) #define cp_write(var, ...) _cp_write(var, __VA_ARGS__) void print_mapping(void *addr) { extern uint32 tt_base_virtual; print("%x: %x\n", addr, *(uint32 *)(tt_base_virtual + (((uint32)addr)>>18))); } static inline int page_intersects(uint32 *page_start, uint32 *lower, uint32 *upper) { return (lower >= page_start && lower < (page_start + (CONFIG_INIT_PAGE_SIZE>>2))) || (upper >= page_start && upper < (page_start + (CONFIG_INIT_PAGE_SIZE>>2))) || (lower < page_start && upper >= (page_start + (CONFIG_INIT_PAGE_SIZE>>2))); } void mmu_reinit() { extern uint32 tt_base_virtual; uint32 *curr_addr, *curr_tt_entry; uint32 virt_phys_offset = kernel_start_virtual() - kernel_start_physical(); /* CAUTION: 1 = 4 bytes */ //get the current translation table base address curr_tt_entry = (uint32 *)tt_base_virtual; //do first loop iteration outside the loop, because we have to check against wrapping back around to know we're done *curr_tt_entry = 0xc02; /* 0xc02 means read/write at any priviledge level, and that it's a section w/o PXN bit set */ curr_tt_entry++; //create identity mapping for entire address space using sections. //BUT, if we've relocated the kernel from where it is in physical //memory, make sure we keep those mappings correct, and we'll actually //swap the two mappings so all of memory is addressable. for (curr_addr = (uint32 *)CONFIG_INIT_PAGE_SIZE; curr_addr != 0; curr_addr += (CONFIG_INIT_PAGE_SIZE>>2)) { if (page_intersects(curr_addr, kernel_start_physical(), kernel_end_physical())) { *curr_tt_entry = (uint32)(curr_addr + virt_phys_offset) | 0xc02; } else if (page_intersects(curr_addr, kernel_start_virtual(), kernel_end_virtual())) { *curr_tt_entry = (uint32)(curr_addr - virt_phys_offset) | 0xc02; } else { *curr_tt_entry = (uint32)curr_addr | 0xc02; } curr_tt_entry++; } }