Home | History | Annotate | Download | only in stm32
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <stdbool.h>
     18 #include <stdint.h>
     19 
     20 #include <bl.h>
     21 #include <cpu.h>
     22 #include <mpu.h>
     23 #include <platform.h>
     24 
     25 #include <plat/cmsis.h>
     26 
     27 #define MPU_REG_DEFAULT     0
     28 #define MPU_REG_ROM         1
     29 #define MPU_REG_RAM         2
     30 #define MPU_REG_PERIPH      3
     31 #define MPU_REG_PRIV_PERIPH 4
     32 
     33 #define MPU_RASR_S          0x00040000
     34 #define MPU_RASR_C          0x00020000
     35 #define MPU_RASR_B          0x00010000
     36 
     37 /* region type */
     38 #define MPU_TYPE_SRAM       (MPU_RASR_S | MPU_RASR_C)
     39 #define MPU_TYPE_FLASH      (MPU_RASR_C)
     40 #define MPU_TYPE_PERIPH     (MPU_RASR_S | MPU_RASR_B)
     41 
     42 /* region execute priviledges */
     43 #define MPU_BIT_XN          (1UL << 28) /* no execute */
     44 
     45 /* region access priviledges */
     46 #define MPU_NA              (0UL << 24) /* S: no access   U: no access */
     47 #define MPU_U_NA_S_RW       (1UL << 24) /* S: RW          U: no access */
     48 #define MPU_U_RO_S_RW       (2UL << 24) /* S: RW          U: RO        */
     49 #define MPU_RW              (3UL << 24) /* S: RW          U: RW        */
     50 #define MPU_U_NA_S_RO       (5UL << 24) /* S: RO          U: no access */
     51 #define MPU_U_RO_S_RO       (6UL << 24) /* S: RO          U: RO        */
     52 
     53 /* subregion disable (not used so all zeroes) */
     54 #define MPU_SRD_BITS        0x0000UL
     55 #define MPU_BIT_ENABLE      1UL
     56 
     57 /* these define rom */
     58 extern uint8_t __shared_end[];
     59 extern uint8_t __ram_start[];
     60 extern uint8_t __ram_end[];
     61 
     62 void MemoryManagemntFault_Handler(void);
     63 void __attribute__((naked)) MemoryManagemntFault_Handler(void)
     64 {
     65     asm volatile(
     66         "mov    r0, #3                    \n"
     67         "b      cpuCommonFaultCode        \n"
     68     );
     69 }
     70 
     71 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 */
     72 {
     73     uint32_t proposedStart, lenVal = 1;
     74     uint64_t len, proposedLen, intState;
     75 
     76     if (start > end)
     77         return false;
     78     else
     79         len = end - start + UINT64_C(1);
     80 
     81     /* expand until it works */
     82     do {
     83         proposedStart = start &~ ((UINT64_C(1) << lenVal) - 1);
     84         proposedLen = start + len - proposedStart;
     85         if (proposedLen < 32)
     86             proposedLen = 32;
     87         lenVal = (proposedLen & (proposedLen - UINT64_C(1))) ? 64 - __builtin_clzll(proposedLen) : 63 - __builtin_clzll(proposedLen);
     88 
     89     } while (proposedStart & ((UINT64_C(1) << lenVal) - UINT64_C(1)));
     90 
     91     /* minimum size: 32 bytes */
     92     if (lenVal < 5)
     93         lenVal = 5;
     94 
     95     intState = cpuIntsOff();
     96     asm volatile("dsb\nisb");
     97 
     98     MPU->RNR = regionNo;
     99     MPU->RASR = 0; /* disable region before changing it */
    100     MPU->RBAR = proposedStart;
    101     MPU->RASR = MPU_SRD_BITS | MPU_BIT_ENABLE | attrs | ((lenVal-1) << 1);
    102 
    103     asm volatile("dsb\nisb");
    104     cpuIntsRestore(intState);
    105 
    106     return true;
    107 }
    108 
    109 static void mpuCfgRom(bool allowSvcWrite)
    110 {
    111     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));
    112 }
    113 
    114 static void mpuCfgRam(bool allowSvcExecute)
    115 {
    116     mpuRegionCfg(MPU_REG_RAM, (uint32_t)&__ram_start, (uint32_t)&__ram_end - 1, MPU_TYPE_SRAM | MPU_RW | (allowSvcExecute ? 0 : MPU_BIT_XN));
    117 }
    118 
    119 
    120 void mpuStart(void)
    121 {
    122     MPU->CTRL = 0x00; // disable MPU
    123 
    124     /* 0x00000000 - 0xFFFFFFFF */
    125     mpuRegionCfg(MPU_REG_DEFAULT, 0, 0xFFFFFFFF, MPU_NA | MPU_BIT_XN);
    126 
    127     mpuCfgRom(false);
    128     mpuCfgRam(false);
    129 
    130     /* 0x40000000 - 0x4003FFFF */
    131     mpuRegionCfg(MPU_REG_PERIPH, 0x40000000, 0x4003FFFF, MPU_TYPE_PERIPH | MPU_U_NA_S_RW | MPU_BIT_XN);
    132 
    133     /* 0xE0000000 - 0xE00FFFFF */
    134     mpuRegionCfg(MPU_REG_PRIV_PERIPH, 0xE0000000, 0xE00FFFFF, MPU_TYPE_PERIPH | MPU_U_NA_S_RW | MPU_BIT_XN);
    135 
    136     //MPU on, even during faults, supervisor default: allow, user default: default deny
    137     MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_HFNMIENA_Msk | MPU_CTRL_PRIVDEFENA_Msk;
    138     SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
    139 }
    140 
    141 void mpuAllowRamExecution(bool allowSvcExecute)
    142 {
    143     mpuCfgRam(allowSvcExecute);
    144 }
    145 
    146 void mpuAllowRomWrite(bool allowSvcWrite)
    147 {
    148     mpuCfgRom(allowSvcWrite);
    149 }
    150 
    151 void mpuShow()
    152 {
    153     int i, regions = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos;
    154     uint32_t addr, rasr;
    155     uint8_t ap;
    156     bool xn;
    157     char *s, *u;
    158 
    159     osLog(LOG_INFO, "MPU: %d HFNMIENA: %d PRIVDEFENA: %d\n",
    160         !!(MPU->CTRL & MPU_CTRL_ENABLE_Msk),
    161         !!(MPU->CTRL & MPU_CTRL_HFNMIENA_Msk),
    162         !!(MPU->CTRL & MPU_CTRL_PRIVDEFENA_Msk));
    163     for (i=0; i<regions; i++) {
    164         MPU->RNR = i;
    165         addr = MPU->RBAR & MPU_RBAR_ADDR_Msk;
    166         rasr = MPU->RASR;
    167         xn = rasr & MPU_RASR_XN_Msk;
    168         ap = (rasr & MPU_RASR_AP_Msk) >> MPU_RASR_AP_Pos;
    169         if (ap == 0) {
    170             s = "---";
    171         } else if (ap == 1 || ap == 2 || ap == 3) {
    172             if (xn)
    173                 s = "RW-";
    174             else
    175                 s = "RWX";
    176         } else if (ap == 5 || ap == 6 || ap == 7) {
    177             if (xn)
    178                 s = "R--";
    179             else
    180                 s = "R-X";
    181         } else {
    182             s = "???";
    183         }
    184         if (ap == 0 || ap == 1 || ap == 5) {
    185             u = "---";
    186         } else if (ap == 3) {
    187             if (xn)
    188                 u = "RW-";
    189             else
    190                 u = "RWX";
    191         } else if (ap == 2 || ap == 6 || ap == 7) {
    192             if (xn)
    193                 u = "R--";
    194             else
    195                 u = "R-X";
    196         } else {
    197             u = "???";
    198         }
    199         osLog(LOG_INFO,
    200             "%d: %c %08lx-%08lx S: %s U: %s TEX: %ld %c%c%c %02lx\n",
    201             i, (rasr & MPU_RASR_ENABLE_Msk) ? 'E' : 'D',
    202             addr,
    203             addr + (1 << (((rasr & MPU_RASR_SIZE_Msk) >> MPU_RASR_SIZE_Pos) + 1))-1,
    204             s, u,
    205             (rasr & MPU_RASR_TEX_Msk) >> MPU_RASR_TEX_Pos,
    206             (rasr & MPU_RASR_S_Msk) ? 'S' : ' ',
    207             (rasr & MPU_RASR_C_Msk) ? 'C' : ' ',
    208             (rasr & MPU_RASR_B_Msk) ? 'B' : ' ',
    209             (rasr & MPU_RASR_SRD_Msk) >> MPU_RASR_SRD_Pos);
    210     }
    211 }
    212