Merge "mpu: actually enable the mpu (for real this time)"
diff --git a/firmware/os/cpu/cortexm4/cpu.c b/firmware/os/cpu/cortexm4/cpu.c
index 5105810..927db35 100644
--- a/firmware/os/cpu/cortexm4/cpu.c
+++ b/firmware/os/cpu/cortexm4/cpu.c
@@ -32,14 +32,23 @@
 #define HARD_FAULT_DROPBOX_MAGIC_HAVE_DROP  0x00002000
 #define HARD_FAULT_DROPBOX_MAGIC_DATA_MASK  0x00001FFF
 
+union TidTrig {
+    struct {
+        uint32_t tid : 16;
+        uint32_t trig : 2;
+        uint32_t RFU : 14;
+    };
+    uint32_t rw;
+};
+
+// These registers only support word accesses (r/w)
+// Make sure to only use uint32_t's
 struct RamPersistedDataAndDropbox {
     uint32_t magic; // and part of dropbox
     uint32_t r[16];
     uint32_t sr_hfsr_cfsr_lo;
     uint32_t bits;
-    uint16_t tid;
-    uint16_t trig:2;
-    uint16_t RFU:14;
+    union TidTrig tid_trig; // only access via tid_trig.rw
 };
 
 /* //if your device persists ram, you can use this instead:
@@ -106,9 +115,10 @@
 
 static void cpuDbxDump(struct RamPersistedDataAndDropbox *dbx)
 {
-    uint32_t i, hfsr, cfsr, sr, code;
+    uint32_t i, hfsr, cfsr, sr;
+    union TidTrig tid_trig;
     const char *trigName;
-    static const char *trigNames[] = { "UNKNOWN", "HARD FAULT", "WDT" };
+    static const char *trigNames[] = { "UNKNOWN", "HARD FAULT", "WDT", "MPU" };
 
     if (dbx) {
         for (i = 0; i < 8; i++)
@@ -120,12 +130,13 @@
         osLog(LOG_ERROR, "  xPSR = 0x%08lX  HFSR = 0x%08lX\n", sr, hfsr);
         osLog(LOG_ERROR, "  CFSR = 0x%08lX  BITS = 0x%08lX\n", cfsr, dbx->bits);
         // reboot source (if known), reported as TRIG
-        // so far we have 2 reboot sources reported here:
+        // so far we have 3 reboot sources reported here:
         // 1 - HARD FAULT
         // 2 - WDT
-        code = dbx->trig;
-        trigName = trigNames[code < ARRAY_SIZE(trigNames) ? code : 0];
-        osLog(LOG_ERROR, "  TID  = 0x%04" PRIX16 "  TRIG = 0x%04" PRIX16 " [%s]\n", dbx->tid, dbx->trig, trigName);
+        // 3 - MPU
+        tid_trig.rw = dbx->tid_trig.rw;
+        trigName = trigNames[tid_trig.trig < ARRAY_SIZE(trigNames) ? tid_trig.trig : 0];
+        osLog(LOG_ERROR, "  TID  = 0x%04" PRIX16 "  TRIG = 0x%04" PRIX16 " [%s]\n\n", tid_trig.tid, tid_trig.trig, trigName);
     }
 }
 
@@ -259,6 +270,7 @@
 {
     struct RamPersistedDataAndDropbox *dbx = getInitedPersistedData();
     uint32_t i, hi;
+    union TidTrig tid_trig;
 
     wdtPing();
 
@@ -273,8 +285,9 @@
 
     cpuPackSrBits(&dbx->sr_hfsr_cfsr_lo, &hi, excRegs[7], SCB->HFSR, SCB->CFSR);
     dbx->magic |= HARD_FAULT_DROPBOX_MAGIC_HAVE_DROP | (hi & HARD_FAULT_DROPBOX_MAGIC_DATA_MASK);
-    dbx->tid = osGetCurrentTid();
-    dbx->trig = code;
+    tid_trig.tid = osGetCurrentTid();
+    tid_trig.trig = code;
+    dbx->tid_trig.rw = tid_trig.rw;
 
     if (!tinyStack) {
         osLog(LOG_ERROR, "*HARD FAULT*\n");
diff --git a/firmware/os/cpu/cortexm4/inc/cpu/cmsis.h b/firmware/os/cpu/cortexm4/inc/cpu/cmsis.h
index d740542..8cb6d37 100644
--- a/firmware/os/cpu/cortexm4/inc/cpu/cmsis.h
+++ b/firmware/os/cpu/cortexm4/inc/cpu/cmsis.h
@@ -22,9 +22,6 @@
 extern "C" {
 #endif
 
-#define __NVIC_PRIO_BITS 4
-#define __FPU_PRESENT 1
-
 #include <cpu/cmsis/core_cm4.h>
 
 #ifdef __cplusplus
diff --git a/firmware/os/inc/mpu.h b/firmware/os/inc/mpu.h
index 45bf7a9..a331bdc 100644
--- a/firmware/os/inc/mpu.h
+++ b/firmware/os/inc/mpu.h
@@ -32,6 +32,7 @@
 void mpuStart(void);
 void mpuAllowRamExecution(bool allowSvcExecute);         /* for Supervisor only, if possible */
 void mpuAllowRomWrite(bool allowSvcWrite);     /* for Supervisor only, if possible */
+void mpuShow(void);
 
 
 #ifdef __cplusplus
diff --git a/firmware/os/platform/stm32/inc/plat/cmsis.h b/firmware/os/platform/stm32/inc/plat/cmsis.h
index 8b79368..53c7f2b 100644
--- a/firmware/os/platform/stm32/inc/plat/cmsis.h
+++ b/firmware/os/platform/stm32/inc/plat/cmsis.h
@@ -24,6 +24,7 @@
 
 #define __NVIC_PRIO_BITS 4
 #define __FPU_PRESENT 1
+#define __MPU_PRESENT 1
 
 
 
diff --git a/firmware/os/platform/stm32/mpu.c b/firmware/os/platform/stm32/mpu.c
index f45a153..1a2f0a3 100644
--- a/firmware/os/platform/stm32/mpu.c
+++ b/firmware/os/platform/stm32/mpu.c
@@ -22,64 +22,75 @@
 #include <mpu.h>
 #include <platform.h>
 
-struct CortexMpu {
-    volatile uint32_t CTRL;
-    volatile uint32_t RNR;
-    volatile uint32_t RBAR;
-    volatile uint32_t RASR;
-};
+#include <plat/cmsis.h>
 
-#define MPU ((struct CortexMpu*)0xE000ED94UL)
+#define MPU_REG_DEFAULT     0
+#define MPU_REG_ROM         1
+#define MPU_REG_RAM         2
+#define MPU_REG_PERIPH      3
+#define MPU_REG_PRIV_PERIPH 4
 
-#define MPU_REG_ROM          0
-#define MPU_REG_RAM          1
-#define MPU_REG_NULL_PAGE    2
-
+#define MPU_RASR_S          0x00040000
+#define MPU_RASR_C          0x00020000
+#define MPU_RASR_B          0x00010000
 
 /* region type */
-#define MPU_TYPE_DEVICE (0x10UL << 16)
-#define MPU_TYPE_MEMORY (0x0FUL << 16)
+#define MPU_TYPE_SRAM       (MPU_RASR_S | MPU_RASR_C)
+#define MPU_TYPE_FLASH      (MPU_RASR_C)
+#define MPU_TYPE_PERIPH     (MPU_RASR_S | MPU_RASR_B)
 
 /* region execute priviledges */
-#define MPU_BIT_XN      (1UL << 28) /* no execute */
+#define MPU_BIT_XN          (1UL << 28) /* no execute */
 
 /* region access priviledges */
-#define MPU_NA          (0UL << 24) /* S: no access   U: no access */
-#define MPU_U_NA_S_RW   (1UL << 24) /* S: RW          U: no access */
-#define MPU_U_RO_S_RW   (2UL << 24) /* S: RW          U: RO        */
-#define MPU_RW          (3UL << 24) /* S: RW          U: RW        */
-#define MPU_U_NA_S_RO   (5UL << 24) /* S: RO          U: no access */
-#define MPU_U_RO_S_RO   (6UL << 24) /* S: RO          U: RO        */
+#define MPU_NA              (0UL << 24) /* S: no access   U: no access */
+#define MPU_U_NA_S_RW       (1UL << 24) /* S: RW          U: no access */
+#define MPU_U_RO_S_RW       (2UL << 24) /* S: RW          U: RO        */
+#define MPU_RW              (3UL << 24) /* S: RW          U: RW        */
+#define MPU_U_NA_S_RO       (5UL << 24) /* S: RO          U: no access */
+#define MPU_U_RO_S_RO       (6UL << 24) /* S: RO          U: RO        */
 
-/* subregion mask (not used so all ones) */
-#define MPU_SRD_BITS    0xFF00UL
-#define MPU_BIT_ENABLE  1UL
+/* subregion disable (not used so all zeroes) */
+#define MPU_SRD_BITS        0x0000UL
+#define MPU_BIT_ENABLE      1UL
 
 /* these define rom */
 extern uint8_t __shared_end[];
 extern uint8_t __ram_start[];
 extern uint8_t __ram_end[];
 
-static void mpuRegionCfg(uint32_t regionNo, uint32_t start, uint32_t len, uint32_t attrs) /* region will be rounded to acceptable boundaries (32B minimum, self-aligned) by GROWTH */
+void MemoryManagemntFault_Handler(void);
+void __attribute__((naked)) MemoryManagemntFault_Handler(void)
 {
-    uint32_t proposedStart, proposedLen, lenVal = 1;
-    uint64_t intState;
+    asm volatile(
+        "mov    r0, #3                    \n"
+        "b      cpuCommonFaultCode        \n"
+    );
+}
+
+static bool mpuRegionCfg(uint32_t regionNo, uint32_t start, uint32_t end, uint32_t attrs) /* region will be rounded to acceptable boundaries (32B minimum, self-aligned) by GROWTH */
+{
+    uint32_t proposedStart, lenVal = 1;
+    uint64_t len, proposedLen, intState;
+
+    if (start > end)
+        return false;
+    else
+        len = end - start + UINT64_C(1);
 
     /* expand until it works */
     do {
-        /* special case 4GB region */
-        if (lenVal == 32) {
-            proposedStart = 0;
-            break;
-        }
-
-        proposedStart = start &~ ((1ULL << lenVal) - 1);
+        proposedStart = start &~ ((UINT64_C(1) << lenVal) - 1);
         proposedLen = start + len - proposedStart;
         if (proposedLen < 32)
             proposedLen = 32;
-        lenVal = (proposedLen & (proposedLen - 1)) ? 32 - __builtin_clz(proposedLen) : 31 - __builtin_clz(proposedLen);
+        lenVal = (proposedLen & (proposedLen - UINT64_C(1))) ? 64 - __builtin_clzll(proposedLen) : 63 - __builtin_clzll(proposedLen);
 
-    } while (proposedStart & ((1ULL << lenVal) - 1));
+    } while (proposedStart & ((UINT64_C(1) << lenVal) - UINT64_C(1)));
+
+    /* minimum size: 32 bytes */
+    if (lenVal < 5)
+        lenVal = 5;
 
     intState = cpuIntsOff();
     asm volatile("dsb\nisb");
@@ -87,30 +98,44 @@
     MPU->RNR = regionNo;
     MPU->RASR = 0; /* disable region before changing it */
     MPU->RBAR = proposedStart;
-    MPU->RASR = MPU_SRD_BITS | MPU_BIT_ENABLE | attrs | (lenVal << 1);
+    MPU->RASR = MPU_SRD_BITS | MPU_BIT_ENABLE | attrs | ((lenVal-1) << 1);
 
     asm volatile("dsb\nisb");
     cpuIntsRestore(intState);
+
+    return true;
 }
 
 static void mpuCfgRom(bool allowSvcWrite)
 {
-    mpuRegionCfg(MPU_REG_ROM, (uint32_t)&BL, __shared_end - (uint8_t*)&BL, MPU_TYPE_MEMORY | (allowSvcWrite ? MPU_U_RO_S_RW : MPU_U_RO_S_RO));
+    mpuRegionCfg(MPU_REG_ROM, (uint32_t)&BL, (uint32_t)&__shared_end - 1, MPU_TYPE_FLASH | (allowSvcWrite ? MPU_U_RO_S_RW : MPU_U_RO_S_RO));
 }
 
 static void mpuCfgRam(bool allowSvcExecute)
 {
-    mpuRegionCfg(MPU_REG_RAM, (uint32_t)&__ram_start, __ram_end - __ram_start, MPU_TYPE_MEMORY | MPU_RW | (allowSvcExecute ? 0 : MPU_BIT_XN));
+    mpuRegionCfg(MPU_REG_RAM, (uint32_t)&__ram_start, (uint32_t)&__ram_end - 1, MPU_TYPE_SRAM | MPU_RW | (allowSvcExecute ? 0 : MPU_BIT_XN));
 }
 
 
 void mpuStart(void)
 {
-    MPU->CTRL = 0x07; //MPU on, even during faults, supervisor default: allow, user default: default deny
+    MPU->CTRL = 0x00; // disable MPU
+
+    /* 0x00000000 - 0xFFFFFFFF */
+    mpuRegionCfg(MPU_REG_DEFAULT, 0, 0xFFFFFFFF, MPU_NA | MPU_BIT_XN);
 
     mpuCfgRom(false);
     mpuCfgRam(false);
-    mpuRegionCfg(MPU_REG_NULL_PAGE, 0, 4096, MPU_TYPE_MEMORY | MPU_NA | MPU_BIT_XN);
+
+    /* 0x40000000 - 0x4003FFFF */
+    mpuRegionCfg(MPU_REG_PERIPH, 0x40000000, 0x4003FFFF, MPU_TYPE_PERIPH | MPU_U_NA_S_RW | MPU_BIT_XN);
+
+    /* 0xE0000000 - 0xE00FFFFF */
+    mpuRegionCfg(MPU_REG_PRIV_PERIPH, 0xE0000000, 0xE00FFFFF, MPU_TYPE_PERIPH | MPU_U_NA_S_RW | MPU_BIT_XN);
+
+    //MPU on, even during faults, supervisor default: allow, user default: default deny
+    MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_HFNMIENA_Msk | MPU_CTRL_PRIVDEFENA_Msk;
+    SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
 }
 
 void mpuAllowRamExecution(bool allowSvcExecute)
@@ -123,3 +148,64 @@
     mpuCfgRom(allowSvcWrite);
 }
 
+void mpuShow()
+{
+    int i, regions = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
+    uint32_t addr, rasr;
+    uint8_t ap;
+    bool xn;
+    char *s, *u;
+
+    osLog(LOG_INFO, "MPU: %d HFNMIENA: %d PRIVDEFENA: %d\n",
+        !!(MPU->CTRL & MPU_CTRL_ENABLE_Msk),
+        !!(MPU->CTRL & MPU_CTRL_HFNMIENA_Msk),
+        !!(MPU->CTRL & MPU_CTRL_PRIVDEFENA_Msk));
+    for (i=0; i<regions; i++) {
+        MPU->RNR = i;
+        addr = MPU->RBAR & MPU_RBAR_ADDR_Msk;
+        rasr = MPU->RASR;
+        xn = rasr & MPU_RASR_XN_Msk;
+        ap = (rasr & MPU_RASR_AP_Msk) >> MPU_RASR_AP_Pos;
+        if (ap == 0) {
+            s = "---";
+        } else if (ap == 1 || ap == 2 || ap == 3) {
+            if (xn)
+                s = "RW-";
+            else
+                s = "RWX";
+        } else if (ap == 5 || ap == 6 || ap == 7) {
+            if (xn)
+                s = "R--";
+            else
+                s = "R-X";
+        } else {
+            s = "???";
+        }
+        if (ap == 0 || ap == 1 || ap == 5) {
+            u = "---";
+        } else if (ap == 3) {
+            if (xn)
+                u = "RW-";
+            else
+                u = "RWX";
+        } else if (ap == 2 || ap == 6 || ap == 7) {
+            if (xn)
+                u = "R--";
+            else
+                u = "R-X";
+        } else {
+            u = "???";
+        }
+        osLog(LOG_INFO,
+            "%d: %c %08lx-%08lx S: %s U: %s TEX: %ld %c%c%c %02lx\n",
+            i, (rasr & MPU_RASR_ENABLE_Msk) ? 'E' : 'D',
+            addr,
+            addr + (1 << (((rasr & MPU_RASR_SIZE_Msk) >> MPU_RASR_SIZE_Pos) + 1))-1,
+            s, u,
+            (rasr & MPU_RASR_TEX_Msk) >> MPU_RASR_TEX_Pos,
+            (rasr & MPU_RASR_S_Msk) ? 'S' : ' ',
+            (rasr & MPU_RASR_C_Msk) ? 'C' : ' ',
+            (rasr & MPU_RASR_B_Msk) ? 'B' : ' ',
+            (rasr & MPU_RASR_SRD_Msk) >> MPU_RASR_SRD_Pos);
+    }
+}