mpu: actually enable the mpu (for real this time)

Change the SRD (subregion disable) bits to 0x00 to enable all subregions
Dump registers on MemoryManagemntFault and reboot
Add mpuShow function to dump mpu setup
Add __MPU_PRESENT #define to stm32 cmsis.h
Fix tid printing (all rtc registers only accept word read/writes)

MPU settings:
MPU: 1 HFNMIENA: 1 PRIVDEFENA: 1
0: E 00000000-ffffffff S: --- U: --- TEX: 0     00
1: E 08000000-0807ffff S: R-X U: R-X TEX: 0  C  00
2: E 20000000-2001ffff S: RW- U: RW- TEX: 0 SC  00
3: E 40000000-4003ffff S: RW- U: --- TEX: 0 S B 00
4: E e0000000-e00fffff S: RW- U: --- TEX: 0 S B 00

Bug: 37756881
Test: read from 0x00000004 and confirm system reboots
Change-Id: I8398ecd838dfeba40f5a12cb332eca0612cbc720
Signed-off-by: Ben Fennema <fennema@google.com>
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);
+    }
+}