aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojtek Kosior <kwojtus@protonmail.com>2019-11-09 11:09:40 +0100
committerWojtek Kosior <kwojtus@protonmail.com>2019-11-09 11:09:40 +0100
commit2fd668c8ebfb5e26cfc6964f0014a7121964a5c2 (patch)
treeb1997086abcedd949ada89407d0a14cad2aa626d
parentd3da1d80ac2ce844b19feab6187722fc72eaa59c (diff)
downloadrpi-MMU-example-2fd668c8ebfb5e26cfc6964f0014a7121964a5c2.tar.gz
rpi-MMU-example-2fd668c8ebfb5e26cfc6964f0014a7121964a5c2.zip
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
-rw-r--r--kernel.c219
-rw-r--r--strings.h9
2 files changed, 205 insertions, 23 deletions
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());
}
diff --git a/strings.h b/strings.h
new file mode 100644
index 0000000..7721f63
--- /dev/null
+++ b/strings.h
@@ -0,0 +1,9 @@
+#include <stdint.h>
+
+void uint32_to_bits(uint32_t number, char *buf)
+{
+ for (int i = 0; i < 32; i++)
+ buf[i] = ((number >> (32 - i - 1)) & 1) ? '1' : '0';
+
+ buf[32] = '\0';
+}