aboutsummaryrefslogtreecommitdiff
path: root/kernel.c
diff options
context:
space:
mode:
authorWojtek Kosior <kwojtus@protonmail.com>2019-11-09 15:36:45 +0100
committerWojtek Kosior <kwojtus@protonmail.com>2019-11-09 15:36:45 +0100
commiteb286810ae841301b7647f3350b29a70d4a479b8 (patch)
tree3967ca19a9b4a04a2e2e19c688c2cdbdea6a5c7e /kernel.c
parentaf9b1bca3ecb1451665d9e859a7af40afb183d14 (diff)
downloadrpi-MMU-example-eb286810ae841301b7647f3350b29a70d4a479b8.tar.gz
rpi-MMU-example-eb286810ae841301b7647f3350b29a70d4a479b8.zip
enable the MMU - a cleaner way (describing registers with bitfield structs and unions)
Diffstat (limited to 'kernel.c')
-rw-r--r--kernel.c218
1 files changed, 78 insertions, 140 deletions
diff --git a/kernel.c b/kernel.c
index dcfac11..8d2fdef 100644
--- a/kernel.c
+++ b/kernel.c
@@ -1,7 +1,8 @@
#include "uart.h"
#include "cpsr.h"
#include "strings.h"
-#include "short_descriptor.h"
+#include "translation_table_descriptors.h"
+#include "cp_regs.h"
extern char __end;
@@ -66,190 +67,127 @@ void kernel_main(uint32_t r0, uint32_t r1, uint32_t atags)
uart_puts("current mode: ");
uart_puts(mode_name);
- uart_puts("setting mode to system...\r\n");
- uart_puts("current mode: ");
+ uart_puts("setting mode to system (PL1)...\r\n");
set_system_mode();
- switch(read_processor_mode())
- {
- 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_name);
-
- char bits[33];
-
- // compute translation table address for TTBR0
+ char bits[33]; // for printing uint32_t bit values
+
+ // compute translation table base address
// 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_t kernel_end = (uint32_t) &__end;
+ uint32_t translation_table_base =
+ ((kernel_end - 1) & ~((uint32_t) 0x3fff)) + (uint32_t) 0x4000;
uint32_to_bits(translation_table_base, bits);
- uart_puts("\n\rbinary representation of chosen"
+ uart_puts("binary representation of chosen"
" lvl1 translation table address: ");
- uart_puts(bits);
+ uart_puts(bits); uart_puts("\n\r");
- 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 :)
+ uart_puts("preparing translation table\n\r");
+ short_descriptor_t *translation_table =
+ (short_descriptor_t*) translation_table_base;
+
for (uint32_t i = 0; i < 4096; i++)
- translation_table[i] = sd_lvl1_make_section(i << 20);
+ translation_table[i].section_fields =
+ (short_section_descriptor_t) {
+ .SECTION_BASE_ADDRESS_31_20 = i,
+ .SECTION_OR_SUPERSECTION_BIT = DESCRIBES_SECTION,
+ .ACCESS_PERMISSIONS_2 = AP_2_0_MODEL_RW_PL1 >> 2,
+ .ACCESS_PERMISSIONS_1_0 = AP_2_0_MODEL_RW_PL1 & 0b011,
+ .DESCRIPTOR_TYPE_2 =
+ SHORT_DESCRIPTOR_SECTION_OR_SUPERSECTION >> 1,
+ // rest of fields are 0s
+ };
- 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"
+ uart_puts("setting 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);
+ DACR_t DACR = 0;
+ DACR = set_domain_permissions(DACR, 0, DOMAIN_CLIENT_ACCESS);
+ for (int i = 1; i < 16; i++)
+ DACR = set_domain_permissions(DACR, i, DOMAIN_NO_ACCESS);
+ // the above should do the same as this:
+ // DACR = 1;
+
+ asm("mcr p15, 0, %0, c3, c0, 0" :: "r" (DACR));
// 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");
+ // some of this is redundant (i.e. MMU should already be disabled)
+ uart_puts("setting 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));
+ SCTLR_t SCTLR;
+ asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (SCTLR.raw));
- asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (SCTLR));
- uint32_to_bits(SCTLR, bits);
-
- uart_puts("new SCTLR contents: ");
- uart_puts(bits);
+ SCTLR.fields.M = 0; // disable MMU
+ SCTLR.fields.C = 0; // disable data cache
+ SCTLR.fields.I = 0; // disable instruction cache
+ SCTLR.fields.TRE = 0; // disable TEX remap
+ SCTLR.fields.AFE = 0; // disable access flag usage
+ asm("mcr p15, 0, %0, c1, c0, 0\n\r"
+ "isb" :: "r" (SCTLR.raw) : "memory");
+ // TODO: move invalidation instructions to some header as inlines
+
+ uart_puts("invalidating instruction cache, branch prediction,"
+ " and entire main TLB\n\r");
+
// 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"
+ asm("mcr p15, 0, r0, c7, c5, 6\n\r" // r0 - same as above
"isb" ::: "memory");
- // invalidate instruction cache
- uart_puts("\n\rinvalidating entire main TLB\n\r");
+ // invalidate main Translation Lookup Buffer
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"
+ // now set TTBCR to use TTBR0 exclusively
+ uart_puts("Setting TTBCR.N to 0, so that"
" TTBR0 is used everywhere\n\r");
-
- TTBCR &= ~((uint32_t) 0x7); // set N to 0
+
+ uint32_t TTBCR = 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);
+ TTBR_t TTBR0;
+ TTBR0.raw = 0;
+ TTBR0.fields.TRANSLATION_TABLE_BASE_ADDRESS =
+ translation_table_base >> 14;
+ // rest of TTBR0 remains 0s
+ asm("mcr p15, 0, %0, c2, c0, 0" :: "r" (TTBR0.raw));
// 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("enabling the MMU\n\r");
- 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));
+ // redundant - we already have SCTLR contents in the variable
+ // asm("mrc p15, 0, %0, c1, c0, 0" : "=r" (SCTLR.raw));
- asm("mrc p15, 0, %0, c1, c0, 0\r\n"
- "isb" : "=r" (SCTLR));
+ SCTLR.fields.M = 1;
- uint32_to_bits(SCTLR, bits);
-
- uart_puts("SCTLR contents after MMU enabling: ");
- uart_puts(bits);
+ asm("mcr p15, 0, %0, c1, c0, 0\n\r"
+ "isb" :: "r" (SCTLR.raw) : "memory");
- skip:
- uart_puts("skip here\n\r");
-
while (1)
- uart_putc(uart_getc());
+ {
+ char c;
+ switch(c = uart_getc())
+ {
+ case '\r':
+ uart_putc('\n');
+ default:
+ uart_putc(c);
+ }
+ }
}