From 2fd668c8ebfb5e26cfc6964f0014a7121964a5c2 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Sat, 9 Nov 2019 11:09:40 +0100 Subject: enable MMU; warning: DO NOT MERGE THIS COMMIT - ONCE I KNOW HOW TO GET THIS WORK I SHALL WRITE SOME USABLE ROUTINES AND STRUCTS INSTEAD OF THIS CRAPPY CODE HERE --- kernel.c | 219 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 196 insertions(+), 23 deletions(-) (limited to 'kernel.c') diff --git a/kernel.c b/kernel.c index a8df084..dcfac11 100644 --- a/kernel.c +++ b/kernel.c @@ -1,6 +1,12 @@ #include "uart.h" #include "cpsr.h" +#include "strings.h" +#include "short_descriptor.h" +extern char __end; + +void enabling_code_from_the_net(void); + void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) { // Declare as unused @@ -41,42 +47,209 @@ void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) // processor mode asm("mrs %0, cpsr" : "=r" (CPSR) :: "memory"); - char *mode; + char *mode_name; switch(read_processor_mode()) { - case 0x10 : mode = "User (PL0)\r\n"; break; - case 0x11 : mode = "FIQ (PL1)\r\n"; break; - case 0x12 : mode = "IRQ (PL1)\r\n"; break; - case 0x13 : mode = "Supervisor (PL1)\r\n"; break; - case 0x16 : mode = "Monitor (PL1)\r\n"; break; - case 0x17 : mode = "Abort (PL1)\r\n"; break; - case 0x1a : mode = "Hyp (PL2)\r\n"; break; - case 0x1b : mode = "Undefined (PL1)\r\n"; break; - case 0x1f : mode = "System (PL1)\r\n"; break; - default : mode = "Unknown mode\r\n"; break; + case MODE_USER : mode_name = "User (PL0)\r\n"; break; + case MODE_FIQ : mode_name = "FIQ (PL1)\r\n"; break; + case MODE_IRQ : mode_name = "IRQ (PL1)\r\n"; break; + case MODE_SUPERVISOR : mode_name = "Supervisor (PL1)\r\n"; break; + case MODE_MONITOR : mode_name = "Monitor (PL1)\r\n"; break; + case MODE_ABORT : mode_name = "Abort (PL1)\r\n"; break; + case MODE_HYPERVISOR : mode_name = "Hyp (PL2)\r\n"; break; + case MODE_UNDEFINED : mode_name = "Undefined (PL1)\r\n"; break; + case MODE_SYSTEM : mode_name = "System (PL1)\r\n"; break; + default : mode_name = "Unknown mode\r\n"; break; } - uart_puts(mode); + uart_puts("current mode: "); + uart_puts(mode_name); + uart_puts("setting mode to system...\r\n"); + uart_puts("current mode: "); set_system_mode(); switch(read_processor_mode()) { - case 0x10 : mode = "User (PL0)\r\n"; break; - case 0x11 : mode = "FIQ (PL1)\r\n"; break; - case 0x12 : mode = "IRQ (PL1)\r\n"; break; - case 0x13 : mode = "Supervisor (PL1)\r\n"; break; - case 0x16 : mode = "Monitor (PL1)\r\n"; break; - case 0x17 : mode = "Abort (PL1)\r\n"; break; - case 0x1a : mode = "Hyp (PL2)\r\n"; break; - case 0x1b : mode = "Undefined (PL1)\r\n"; break; - case 0x1f : mode = "System (PL1)\r\n"; break; - default : mode = "Unknown mode\r\n"; break; + case MODE_USER : mode_name = "User (PL0)\r\n"; break; + case MODE_FIQ : mode_name = "FIQ (PL1)\r\n"; break; + case MODE_IRQ : mode_name = "IRQ (PL1)\r\n"; break; + case MODE_SUPERVISOR : mode_name = "Supervisor (PL1)\r\n"; break; + case MODE_MONITOR : mode_name = "Monitor (PL1)\r\n"; break; + case MODE_ABORT : mode_name = "Abort (PL1)\r\n"; break; + case MODE_HYPERVISOR : mode_name = "Hyp (PL2)\r\n"; break; + case MODE_UNDEFINED : mode_name = "Undefined (PL1)\r\n"; break; + case MODE_SYSTEM : mode_name = "System (PL1)\r\n"; break; + default : mode_name = "Unknown mode\r\n"; break; } - uart_puts(mode); + uart_puts(mode_name); + + char bits[33]; + + // compute translation table address for TTBR0 + // translation table shall start at first 2^14-bytes aligned + // address after the kernel image + // uint32_t kernel_end = (uint32_t) &__end; + uint32_t translation_table_base = 0x4000; // for now try 0x4000 + // ((kernel_end - 1) & ~((uint32_t) 0x3fff)) + (uint32_t) 0x4000; + + uint32_to_bits(translation_table_base, bits); + uart_puts("\n\rbinary representation of chosen" + " lvl1 translation table address: "); + uart_puts(bits); + + uart_puts("\n\rpreparing translation table\n\r"); + uint32_t *translation_table = (uint32_t*) translation_table_base; + + // flat map all memory + translation_table[0] = sd_lvl1_make_section(0x0); + // make all other entries in translation table invalid :) + for (uint32_t i = 0; i < 4096; i++) + translation_table[i] = sd_lvl1_make_section(i << 20); + + uint32_to_bits(translation_table[0], bits); + uart_puts("translation_table_entry 0: \n\r"); + uart_puts(bits); + + // uart_puts("\n\renabling the MMU\n\r"); + // asm volatile("" ::: "memory"); + // enabling_code_from_the_net(); + // goto skip; + + + // meddle with domain settings + uint32_t DACR; + asm("mrc p15, 0, %0, c3, c0, 0" : "=r" (DACR)); + uint32_to_bits(DACR, bits); + + uart_puts("initial DACR contents: "); + uart_puts(bits); + + uart_puts("\n\rsetting domain0 to client access" + " and blocking other domains\n\r"); + + DACR = 1; + asm("mcr p15, 0, %0, c3, c0, 0" :: "r" (DACR)); + + asm("mrc p15, 0, %0, c3, c0, 0" : "=r" (DACR)); + uint32_to_bits(DACR, bits); + + uart_puts("new DACR contents: "); + uart_puts(bits); + + + // meddle with SCTLR, which determines how some bits in + // table descriptors work and also controls caches + // we don't want to use access flag, so we set AFE to 0 + // we don't want TEX remap, so we set TRE to 0 + // we also disable data and instruction caches and the MMU + uint32_t SCTLR; + asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (SCTLR)); + uint32_to_bits(SCTLR, bits); + + uart_puts("\n\rSCTLR contents: "); + uart_puts(bits); + + uart_puts("\n\rsetting C, I, AFE and TRE to 0 in SCTLR\n\r"); + + SCTLR &= ~((((uint32_t) 1) << 29) | + (((uint32_t) 1) << 28) | + (((uint32_t) 1) << 12) | + (((uint32_t) 1) << 2)); // set AFE and TRE to 0 + asm("mcr p15, 0, %0, c1, c0, 0\n\r" + "isb" :: "r" (SCTLR)); + + asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (SCTLR)); + uint32_to_bits(SCTLR, bits); + + uart_puts("new SCTLR contents: "); + uart_puts(bits); + + // invalidate instruction cache + uart_puts("\n\rinvalidating instruction cache\n\r"); + asm("mcr p15, 0, r0, c7, c5, 0\n\r" // r0 gets ignored + "isb" ::: "memory"); + + // invalidate branch-prediction + uart_puts("\n\rinvalidating branch-prediction\n\r"); + asm("mcr p15, 0, r0, c7, c5, 6\n\r" + "isb" ::: "memory"); + + // invalidate instruction cache + uart_puts("\n\rinvalidating entire main TLB\n\r"); + asm("mcr p15, 0, %0, c8, c7, 0\n\r" + "isb" :: "r" (0) : "memory"); + // now see what's in TTBCR + // set it use TTBR0 exclusively + uint32_t TTBCR; + asm("mrc p15, 0, %0, c2, c0, 2" : "=r" (TTBCR)); + uint32_to_bits(TTBCR, bits); + + uart_puts("\n\rTTBCR contents: "); + uart_puts(bits); + + uart_puts("\n\rSetting TTBCR.N to 0, so that" + " TTBR0 is used everywhere\n\r"); + + TTBCR &= ~((uint32_t) 0x7); // set N to 0 + asm("mcr p15, 0, %0, c2, c0, 2" :: "r" (TTBCR)); + + asm("mrc p15, 0, %0, c2, c0, 2" : "=r" (TTBCR)); + uint32_to_bits(TTBCR, bits); + + uart_puts("new TTBCR contents: "); + uart_puts(bits); + + + // Now do stuff with TTBR0 + uint32_t TTBR0; + asm("mrc p15, 0, %0, c2, c0, 0" : "=r" (TTBR0)); + uint32_to_bits(TTBR0, bits); + + uart_puts("\n\rTTBR0 contents: "); + uart_puts(bits); + + uart_puts("\n\r"); + + TTBR0 = ((TTBR0 << 18) >> 18) | translation_table_base; + TTBR0 &= ~((uint32_t) 0x1a); // set RGN and S in TTBR0 to 0 + asm("mcr p15, 0, %0, c2, c0, 0" :: "r" (TTBR0)); + + asm("mrc p15, 0, %0, c2, c0, 0" : "=r" (TTBR0)); + uint32_to_bits(TTBR0, bits); + + uart_puts("new TTBR0 contents: "); + uart_puts(bits); + + + // enable MMU + asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (SCTLR)); + uint32_to_bits(SCTLR, bits); + + uart_puts("\n\rSCTLR contents before MMU enabling: "); + uart_puts(bits); + + uart_puts("\n\renabling the MMU\n\r"); + + // set M to 0 + SCTLR |= (uint32_t) 1; + + asm("mcr p15, 0, %0, c1, c0, 0" :: "r" (SCTLR)); + + asm("mrc p15, 0, %0, c1, c0, 0\r\n" + "isb" : "=r" (SCTLR)); + + uint32_to_bits(SCTLR, bits); + + uart_puts("SCTLR contents after MMU enabling: "); + uart_puts(bits); + + skip: + uart_puts("skip here\n\r"); + while (1) uart_putc(uart_getc()); } -- cgit v1.2.3