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);
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 
mpuRegionCfg(uint32_t regionNo,uint32_t start,uint32_t end,uint32_t attrs)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 
mpuCfgRom(bool allowSvcWrite)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 
mpuCfgRam(bool allowSvcExecute)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 
mpuStart(void)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 
mpuAllowRamExecution(bool allowSvcExecute)141 void mpuAllowRamExecution(bool allowSvcExecute)
142 {
143     mpuCfgRam(allowSvcExecute);
144 }
145 
mpuAllowRomWrite(bool allowSvcWrite)146 void mpuAllowRomWrite(bool allowSvcWrite)
147 {
148     mpuCfgRom(allowSvcWrite);
149 }
150 
mpuShow()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