#include "kern/mpu/mpu_manager.h" #include "arch.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); 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); MPU.rba_r = rbar; MPU.ras_r = rasr; } static int find_unused_region_slot() { // memory_region_opts_t memory_regions[8]; int i; for (i = 0; i < sizeof(memory_regions) / sizeof(memory_region_opts_t); ++i) { if (!memory_regions[i].enable) { return i; } } return i; } void configure_peripheral_region( void* peripheral_base, region_size_t region_size, privilege_t priv) { int idx = find_unused_region_slot(); memory_region_opts_t memopts = {0}; memopts.region = peripheral_base; memopts.bufferable = 1; memopts.cacheable = 0; memopts.sharable = 1; memopts.tex = 0; memopts.size = region_size; switch (priv) { case NOT_PRIVILEGED: memopts.perms = ACCESS_PERMS_FULL; break; case PRIVILEGED: memopts.perms = ACCESS_PERMS_ONLY_PRIV; break; } memopts.subregion_disable = 0; memopts.executable = 0; memopts.enable = 1; mpu_configure_region(idx, &memopts); } void configure_flash_region( void* flash_base, region_size_t region_size, privilege_t priv) { int idx = find_unused_region_slot(); memory_region_opts_t memopts = {0}; memopts.region = flash_base; memopts.bufferable = 0; memopts.cacheable = 1; memopts.sharable = 0; memopts.tex = 0; memopts.size = region_size; switch (priv) { case NOT_PRIVILEGED: memopts.perms = ACCESS_PERMS_BOTH_RO; break; case PRIVILEGED: memopts.perms = ACCESS_PERMS_ONLY_PRIV_RO; break; } memopts.subregion_disable = 0; memopts.executable = 1; memopts.enable = 1; mpu_configure_region(idx, &memopts); } void configure_ram_region( void* ram_base, region_size_t region_size, privilege_t priv) { int idx = find_unused_region_slot(); memory_region_opts_t memopts = {0}; memopts.region = ram_base; memopts.bufferable = 0; memopts.cacheable = 1; memopts.sharable = 0; memopts.tex = 0; memopts.size = region_size; switch (priv) { case NOT_PRIVILEGED: memopts.perms = ACCESS_PERMS_FULL; break; case PRIVILEGED: memopts.perms = ACCESS_PERMS_ONLY_PRIV; break; } memopts.subregion_disable = 0; memopts.executable = 0; memopts.enable = 1; mpu_configure_region(idx, &memopts); }