aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2020-11-25 11:27:45 -0700
committerJosh Rahm <joshuarahm@gmail.com>2020-11-25 11:32:16 -0700
commitd7d50cc81f72d1275140d7a15c52b6f9e272896f (patch)
tree875b7ed438412c3fc09ff49b58391787813e3998
parentc29e0323020e0f96932d0f9b09747d5b2e28e5a6 (diff)
downloadstm32l4-d7d50cc81f72d1275140d7a15c52b6f9e272896f.tar.gz
stm32l4-d7d50cc81f72d1275140d7a15c52b6f9e272896f.tar.bz2
stm32l4-d7d50cc81f72d1275140d7a15c52b6f9e272896f.zip
Add module for controlling the MPU.
The MPU is a module in arm chips which allow for memory access protection. They are more primitive than full MMUs, but can still provide at least basic access control between different process controls.
-rw-r--r--include/arch/arm/arch.h7
-rw-r--r--include/arch/arm/cortex-m4/mpu.h40
-rw-r--r--include/arch/x86_64/arch.h5
-rw-r--r--include/kern/common.h2
-rw-r--r--include/kern/mpu/mpu_manager.h84
-rw-r--r--src/kern/main.c99
-rw-r--r--src/kern/mpu/mpu_manager.c63
-rw-r--r--test_harness/fake_env.c1
-rw-r--r--test_harness/fake_env.h1
9 files changed, 295 insertions, 7 deletions
diff --git a/include/arch/arm/arch.h b/include/arch/arm/arch.h
index bf96fae..e4ebb8d 100644
--- a/include/arch/arm/arch.h
+++ b/include/arch/arm/arch.h
@@ -13,6 +13,12 @@
#define disable_all_interrupts() \
asm volatile(" cpsid i ")
+#define __isb() \
+ asm volatile(" isb ")
+
+#define __dsb() \
+ asm volatile(" dsb ")
+
#define DMA1_BASE (0x40020000)
#define DMA2_BASE (0x40020400)
@@ -36,6 +42,7 @@
#define SPI3_BASE (0x40003C00)
#define STACK_TOP (0x2000c000)
+#define MPU_BASE (0xE000ED90)
#include <stdint.h>
#ifndef DRY_RUN
diff --git a/include/arch/arm/cortex-m4/mpu.h b/include/arch/arm/cortex-m4/mpu.h
new file mode 100644
index 0000000..fedaf79
--- /dev/null
+++ b/include/arch/arm/cortex-m4/mpu.h
@@ -0,0 +1,40 @@
+#ifndef ARCH_ARM_CORTEX_M4_MPU_H_
+#define ARCH_ARM_CORTEX_M4_MPU_H_
+
+#include "arch.h"
+
+typedef volatile struct {
+ volatile uint32_t type_r;
+#define mpu_en (1 << 0)
+ volatile uint32_t ctrl_r;
+ volatile uint32_t rn_r;
+
+ /**
+ * On the ARM Cortex-M4 processor, the
+ */
+ volatile union {
+#define mpu_size (0x1F << 1)
+#define mpu_srd (0xFF << 8)
+#define mpu_b (1 << 16)
+#define mpu_c (1 << 17)
+#define mpu_s (1 << 18)
+#define mpu_tex (7 << 19)
+#define mpu_ap (3 << 24)
+#define mpu_xn (1 << 28)
+
+#define mpu_valid (1 << 4)
+#define mpu_region (0xF << 0)
+ struct {
+ uint32_t rba_r;
+ uint32_t ras_r;
+ };
+ struct {
+ uint32_t rba_r;
+ uint32_t ras_r;
+ } aliased[4];
+ };
+} mpu_t;
+
+#define MPU (*((mpu_t*)(MPU_BASE)))
+
+#endif /* ARCH_ARM_CORTEX_M4_MPU_H_ */
diff --git a/include/arch/x86_64/arch.h b/include/arch/x86_64/arch.h
index 62ef730..ab26d1e 100644
--- a/include/arch/x86_64/arch.h
+++ b/include/arch/x86_64/arch.h
@@ -5,8 +5,11 @@
#include "fake_env.h"
#define ARCH_PC
+
#define enable_all_interrupts() do {} while(0)
#define disable_all_interrupts() do {} while(0)
+#define __isb() do {} while(0)
+#define __dsb() do {} while(0)
#define RCC_BASE (load_fake_rcc__())
@@ -30,6 +33,8 @@
#define SPI1_BASE (load_fake_spi1__())
#define SPI3_BASE (load_fake_spi3__())
+#define MPU_BASE (load_fake_mpu__())
+
// Pretend there's a data segement at the start of SRAM1 for more accurate
// testing.
#define GHOST_DATA_SEGMENT_SIZE 1200
diff --git a/include/kern/common.h b/include/kern/common.h
index 653279e..c5afe3f 100644
--- a/include/kern/common.h
+++ b/include/kern/common.h
@@ -19,7 +19,7 @@
#define CTZ(n) __builtin_ctz(n)
-#define bool int
+#define bool unsigned int
#ifndef __cplusplus
#define true 1
#define false 0
diff --git a/include/kern/mpu/mpu_manager.h b/include/kern/mpu/mpu_manager.h
new file mode 100644
index 0000000..5e0bc7b
--- /dev/null
+++ b/include/kern/mpu/mpu_manager.h
@@ -0,0 +1,84 @@
+#ifndef KERN_MPU_MPU_MANAGER_H_
+#define KERN_MPU_MPU_MANAGER_H_
+
+#include "kern/common.h"
+
+typedef enum {
+ REGION_SIZE_32 = 4,
+ REGION_SIZE_64 = 5,
+ REGION_SIZE_128 = 6,
+ REGION_SIZE_256 = 7,
+ REGION_SIZE_512 = 8,
+ REGION_SIZE_1Kb = 9,
+ REGION_SIZE_2Kb = 10,
+ REGION_SIZE_4Kb = 11,
+ REGION_SIZE_8Kb = 12,
+ REGION_SIZE_16Kb = 13,
+ REGION_SIZE_32Kb = 14,
+ REGION_SIZE_64Kb = 15,
+ REGION_SIZE_128Kb = 16,
+ REGION_SIZE_256Kb = 17,
+ REGION_SIZE_512Kb = 18,
+ REGION_SIZE_1Mb = 19,
+ REGION_SIZE_2Mb = 20,
+ REGION_SIZE_4Mb = 21,
+ REGION_SIZE_8Mb = 22,
+ REGION_SIZE_16Mb = 23,
+ REGION_SIZE_32Mb = 24,
+ REGION_SIZE_64Mb = 25,
+ REGION_SIZE_128Mb = 26,
+ REGION_SIZE_256Mb = 27,
+ REGION_SIZE_512Mb = 28,
+ REGION_SIZE_1Gb = 29,
+ REGION_SIZE_2Gb = 30,
+ REGION_SIZE_4Gb = 31,
+} region_size_t;
+
+#define region_size_mask(region_size) ((1 << (region_size)) - 1)
+
+typedef enum {
+ /* Neither Privileged nor non-Privileged code cannnot access this region */
+ ACCESS_PERMS_NO_ACCESS = 0,
+
+ /* Only privileged users can access this memory. */
+ ACCESS_PERMS_ONLY_PERMS = 1,
+
+ /* Privileged code can access fully, but non-privilege only has Read-only
+ access.*/
+ ACCESS_NON_PERMS_RO = 2,
+
+ /* Both Privileged and non-Privileged code can access this region fully. */
+ ACCESS_PERMS_FULL = 3,
+
+ /* Only privileged users can access this memory, and only as Read-only. */
+ ACCESS_PERMS_ONLY_PRIV_RO = 5,
+
+ /* Both privileged and non-privileged users can access this memory, but only
+ as Read-only.*/
+ ACCESS_PERMS_BOTH_RO = 5,
+} access_perms_t;
+
+typedef struct {
+ region_size_t size;
+ uint8_t subregion_disable;
+
+ struct {
+ bool enable : 1;
+ bool sharable : 1;
+ bool cacheable : 1;
+ bool bufferable : 1;
+ bool executable : 1;
+ uint8_t tex : 3;
+ };
+
+ access_perms_t perms;
+ void* region;
+} memory_region_opts_t;
+
+void mpu_set_enabled(bool enabled);
+
+/* Configures a memory region. The region number must be on the interval [0,8).
+ */
+void mpu_configure_region(int region_number, memory_region_opts_t* opts);
+
+#endif /* KERN_MPU_MPU_MANAGER_H_ */
diff --git a/src/kern/main.c b/src/kern/main.c
index c85decb..e3995b1 100644
--- a/src/kern/main.c
+++ b/src/kern/main.c
@@ -1,10 +1,17 @@
#include "arch.h"
+#include "arch/arm/cortex-m4/mpu.h"
#include "arch/stm32l4xxx/peripherals/clock.h"
#include "arch/stm32l4xxx/peripherals/system.h"
-#include "kern/log.h"
-#include "kern/panic.h"
#include "kern/init.h"
+#include "kern/log.h"
#include "kern/mem.h"
+#include "kern/mpu/mpu_manager.h"
+#include "kern/panic.h"
+
+void on_hard_fault()
+{
+ panic("Hard fault encountered!\n");
+}
void on_systick() /* Overrides weak-symbol on_systick. */
{
@@ -13,6 +20,8 @@ void on_systick() /* Overrides weak-symbol on_systick. */
#ifdef ARCH_STM32L4
+int thing_in_sram_1;
+
/* Main function. This gets executed from the interrupt vector defined above. */
int main()
{
@@ -20,18 +29,96 @@ int main()
klogf("Heap Start: %p\n", &HEAP_START);
klogf("Heap End : %p\n", &HEAP_STOP);
+ klogf("mpu: %p\n", &MPU);
+ klogf("mpu.type_r: %p\n", MPU.type_r);
+ klogf("mpu.ctrl_r: %p\n", MPU.ctrl_r);
+ klogf("mpu.rn_r: %p\n", MPU.rn_r);
+
+ thing_in_sram_1 = 0xdeadbeef;
+
+ uint32_t control;
+ asm volatile("mrs %0, control" : "=r"(control) :);
+
/* Set the countdown to start from 10,000,0000. */
SCB.strv_r = 10000000 / 20;
/* Enable interrupts. */
- regset(SCB.stcs_r, scb_tickint, 1);
+ // regset(SCB.stcs_r, scb_tickint, 1);
/* Start the systick. */
regset(SCB.stcs_r, scb_enable, 1);
- void* hunk = kalloc(25);
- kfree(hunk);
- kfree(hunk); /* Invalid free. */
+
+ klogf("&thing_in_sram_1: %p\n", &thing_in_sram_1);
+ klogf(" thing_in_sram_1: %p\n", thing_in_sram_1);
+ mpu_set_enabled(0);
+
+ memory_region_opts_t memopts = { 0 };
+ memopts.region = (void*) 0x08000000 /* Flash base */ ;
+ memopts.bufferable = 0;
+ memopts.cacheable = 1;
+ memopts.sharable = 0;
+ memopts.tex = 0;
+ memopts.size = REGION_SIZE_256Kb;
+ memopts.perms = ACCESS_PERMS_BOTH_RO;
+ memopts.subregion_disable = 0;
+ memopts.executable = 1;
+ memopts.enable = 1;
+
+ mpu_configure_region(0, &memopts);
+
+ memopts.region = (void*) SRAM1_BASE;
+ memopts.bufferable = 0;
+ memopts.cacheable = 1;
+ memopts.sharable = 0;
+ memopts.tex = 0;
+ memopts.size = REGION_SIZE_32Kb;
+ memopts.perms = ACCESS_PERMS_FULL;
+ memopts.subregion_disable = 0;
+ memopts.executable = 1;
+ memopts.enable = 1;
+
+ mpu_configure_region(1, &memopts);
+
+ memopts.region = (void*) SRAM2_BASE;
+ memopts.bufferable = 0;
+ memopts.cacheable = 1;
+ memopts.sharable = 0;
+ memopts.tex = 0;
+ memopts.size = REGION_SIZE_16Kb;
+ memopts.perms = ACCESS_PERMS_FULL;
+ memopts.subregion_disable = 0;
+ memopts.executable = 1;
+ memopts.enable = 1;
+
+ mpu_configure_region(2, &memopts);
+
+ for (uint32_t i = 0; i < 8; ++ i) {
+ MPU.rn_r = i;
+ klogf("--- %d ---\n", i);
+ klogf("mpu: %p\n", &MPU);
+ klogf("mpu.type_r: %p\n", MPU.type_r);
+ klogf("mpu.ctrl_r: %p\n", MPU.ctrl_r);
+ klogf("mpu.rn_r: %p\n", MPU.rn_r);
+ klogf("mpu.ras_r: %p\n", MPU.ras_r);
+ klogf("mpu.rba_r: %p\n", MPU.rba_r);
+ }
+
+ // memopts.region = (void*) (SRAM1_BASE);
+ // memopts.bufferable = 0;
+ // memopts.cacheable = 1;
+ // memopts.sharable = 1;
+ // memopts.tex = 0;
+ // memopts.size = REGION_SIZE_16Kb;
+ // memopts.perms = ACCESS_PERMS_NO_ACCESS;
+
+ klogf("MPU not enabled\n");
+ mpu_set_enabled(1);
+ for(;;);
+ // klogf("MPU enabled\n");
+
+ // klogf("&thing_in_sram_1: %p\n", &thing_in_sram_1);
+ // klogf(" thing_in_sram_1: %p\n", thing_in_sram_1);
}
#endif
diff --git a/src/kern/mpu/mpu_manager.c b/src/kern/mpu/mpu_manager.c
new file mode 100644
index 0000000..614766a
--- /dev/null
+++ b/src/kern/mpu/mpu_manager.c
@@ -0,0 +1,63 @@
+#include "arch.h"
+#include "kern/mpu/mpu_manager.h"
+
+#include "arch/arm/cortex-m4/mpu.h"
+#include "kern/common.h"
+#include "kern/log.h"
+#include "kern/panic.h"
+
+memory_region_opts_t memory_regions[8];
+
+void mpu_set_enabled(bool enabled)
+{
+ if (enabled) {
+ regset(MPU.ctrl_r, mpu_en, 1);
+ __isb();
+ __dsb();
+ } else {
+ regset(MPU.ctrl_r, mpu_en, 0);
+ }
+}
+
+void mpu_configure_region(int region_number, memory_region_opts_t* opts)
+{
+ if (region_number >= 8) {
+ panic("MPU can only handle 8 regions.");
+ }
+
+ memory_regions[region_number] = *opts;
+
+ uint32_t region = ptr2reg(opts->region);
+
+ if (opts->size == REGION_SIZE_4Gb && region != 0) {
+ panic("Region pointer must be 0 for region size of 4Gb");
+ } else if ((region & region_size_mask(opts->size))) {
+ panic("Memory region MUST be aligned with given size.");
+ }
+
+ MPU.rn_r = region_number;
+
+ uint32_t rbar = region;
+ regset(rbar, mpu_region, region_number);
+ regset(rbar, mpu_valid, 1);
+
+ klogf("Writing RBAR: %p\n", rbar);
+
+ uint32_t rasr = 0;
+ regset(rasr, mpu_en, opts->enable);
+ regset(rasr, mpu_size, opts->size);
+ regset(rasr, mpu_srd, opts->subregion_disable);
+
+ regset(rasr, mpu_b, opts->bufferable);
+ regset(rasr, mpu_c, opts->cacheable);
+ regset(rasr, mpu_s, opts->sharable);
+
+ regset(rasr, mpu_tex, opts->tex);
+ regset(rasr, mpu_ap, opts->perms);
+ regset(rasr, mpu_xn, !opts->executable);
+
+ klogf("Writing RASR: %p\n", rasr);
+
+ MPU.rba_r = rbar;
+ MPU.ras_r = rasr;
+}
diff --git a/test_harness/fake_env.c b/test_harness/fake_env.c
index fbe85ce..261e9e2 100644
--- a/test_harness/fake_env.c
+++ b/test_harness/fake_env.c
@@ -57,6 +57,7 @@ DEFINE_MEMORY_SEGMENT(nvic, 0xE000E004, 0xE000E4F0)
/* SRAM */
DEFINE_MEMORY_SEGMENT(sram1, 0x20000000, 0x2000C000)
DEFINE_MEMORY_SEGMENT(sram2, 0x2000C000, 0x20018000)
+DEFINE_MEMORY_SEGMENT(mpu, 0xE000ED90, 0xE000EDA4)
/* Serial Peripheral Interface */
DEFINE_MEMORY_SEGMENT(spi1, 0x40013000, 0x400133FF)
diff --git a/test_harness/fake_env.h b/test_harness/fake_env.h
index 34056f4..b4451df 100644
--- a/test_harness/fake_env.h
+++ b/test_harness/fake_env.h
@@ -14,6 +14,7 @@ void* load_fake_nvic__();
void* load_fake_rcc__();
void* load_fake_spi1__();
void* load_fake_spi3__();
+void* load_fake_mpu__();
void wipeout_fake_env();