diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2020-11-25 11:27:45 -0700 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2020-11-25 11:32:16 -0700 |
commit | d7d50cc81f72d1275140d7a15c52b6f9e272896f (patch) | |
tree | 875b7ed438412c3fc09ff49b58391787813e3998 | |
parent | c29e0323020e0f96932d0f9b09747d5b2e28e5a6 (diff) | |
download | stm32l4-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.h | 7 | ||||
-rw-r--r-- | include/arch/arm/cortex-m4/mpu.h | 40 | ||||
-rw-r--r-- | include/arch/x86_64/arch.h | 5 | ||||
-rw-r--r-- | include/kern/common.h | 2 | ||||
-rw-r--r-- | include/kern/mpu/mpu_manager.h | 84 | ||||
-rw-r--r-- | src/kern/main.c | 99 | ||||
-rw-r--r-- | src/kern/mpu/mpu_manager.c | 63 | ||||
-rw-r--r-- | test_harness/fake_env.c | 1 | ||||
-rw-r--r-- | test_harness/fake_env.h | 1 |
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(); |