Skip to content

Instantly share code, notes, and snippets.

@Thalhammer
Created July 13, 2019 19:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Thalhammer/da550b3bc1040699f01e34a9a877837c to your computer and use it in GitHub Desktop.
Save Thalhammer/da550b3bc1040699f01e34a9a877837c to your computer and use it in GitHub Desktop.
RPI mmu
#include "mmu.h"
#include "dmesg.h"
#include <rpi/console.h>
namespace sys {
union mmu_descriptor {
uint32_t as_uint;
struct {
uint32_t state: 2;
uint32_t writebuffer: 1;
uint32_t cachable: 1;
uint32_t sbz2: 1;
uint32_t domain: 2;
uint32_t imp: 1;
uint32_t ap: 2;
uint32_t tex: 3;
uint32_t sbz: 5;
uint32_t base: 12;
};
};
static_assert(sizeof(mmu_descriptor) == sizeof(uint32_t));
extern "C" void mmu_init(void* ptr);
extern "C" void tlb_invalidate();
// Visual code complains such a large alignment, but gcc is fine and it works!
static mmu_descriptor base_table[4096] __attribute__ ((aligned(0x4000)));
void mmu::mmu_enable() noexcept {
mmu_init(base_table);
}
void mmu::init() noexcept {
dmesg::log("mmu","mmu base table = 0x%08x", (uint32_t)&base_table);
memset(base_table, 0, sizeof(base_table));
// Map memory as cachable
for(size_t i = 0; i < 512; i++) // TODO: Automatic ram size detection
map_section(i*(1 << 20), i*(1 << 20), true, true);
// Map io as non cachable
for(size_t i = 0; i < 16; i++)
map_section(0x20000000 + i*(1 << 20), 0x20000000 + i*(1 << 20), false, false);
dmesg::log("mmu", "entry: %u %u %u %u %u %u %u %u %u %u", base_table[0].base, base_table[0].sbz, base_table[0].tex, base_table[0].ap, base_table[0].imp, base_table[0].domain, base_table[0].sbz2, base_table[0].cachable, base_table[0].writebuffer, base_table[0].state);
mmu_enable();
dmesg::log("mmu", "mmu enabled");
}
bool mmu::map_section(uint32_t virt, uint32_t phys, bool cachable, bool wrtbuffer) noexcept {
// mask lower 20 bits of physical address then ORR flags and 0x02 for 1 MiB
uint32_t physval = (phys & 0xfff00000) | (((cachable ? 0x08 : 0) | (wrtbuffer ? 0x04 : 0)) & 0x7ffc) | 0x02 | (0b11 << 8);
base_table[virt >> 20].as_uint = physval;
return true;
}
}
.global mmu_init
mmu_init:
mov r1,#0
// invalidate caches
mcr p15,0,r1,c7,c7,0
// invalidate TLB entries
mcr p15,0,r1,c8,c7,0
// data synchronisation barrier
mcr p15,0,r1,c7,c10,4
// set all domains
ldr r1, =0xffffffff
mcr p15,0,r1,c3,c0,0
// set the translation table base address (remember to align 16 KiB!)
mcr p15,0,r0,c2,c0,0
// set the bits mentioned above
ldr r1, =0x00401805
//ldr r1, =0x00000001
mrc p15,0,r2,c1,c0,0
orr r2,r2,r1
mcr p15,0,r2,c1,c0,0
bx lr
.globl mmu_deinit
mmu_deinit:
mrc p15,0,r2,c1,c0,0
bic r2,#0x1000
bic r2,#0x0004
bic r2,#0x0001
mcr p15,0,r2,c1,c0,0
bx lr
.globl tlb_invalidate
tlb_invalidate:
mov r2,#0
// invalidate TLB entries
mcr p15,0,r1,c8,c7,0
// data synchronisation barrier
mcr p15,0,r1,c7,c10,4
mov pc,lr
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment