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 struct CortexMpu {
26 volatile uint32_t CTRL;
27 volatile uint32_t RNR;
28 volatile uint32_t RBAR;
29 volatile uint32_t RASR;
30 };
31
32 #define MPU ((struct CortexMpu*)0xE000ED94UL)
33
34 #define MPU_REG_ROM 0
35 #define MPU_REG_RAM 1
36 #define MPU_REG_NULL_PAGE 2
37
38
39 /* region type */
40 #define MPU_TYPE_DEVICE (0x10UL << 16)
41 #define MPU_TYPE_MEMORY (0x0FUL << 16)
42
43 /* region execute priviledges */
44 #define MPU_BIT_XN (1UL << 28) /* no execute */
45
46 /* region access priviledges */
47 #define MPU_NA (0UL << 24) /* S: no access U: no access */
48 #define MPU_U_NA_S_RW (1UL << 24) /* S: RW U: no access */
49 #define MPU_U_RO_S_RW (2UL << 24) /* S: RW U: RO */
50 #define MPU_RW (3UL << 24) /* S: RW U: RW */
51 #define MPU_U_NA_S_RO (5UL << 24) /* S: RO U: no access */
52 #define MPU_U_RO_S_RO (6UL << 24) /* S: RO U: RO */
53
54 /* subregion mask (not used so all ones) */
55 #define MPU_SRD_BITS 0xFF00UL
56 #define MPU_BIT_ENABLE 1UL
57
58 /* these define rom */
59 extern uint8_t __shared_end[];
60 extern uint8_t __ram_start[];
61 extern uint8_t __ram_end[];
62
mpuRegionCfg(uint32_t regionNo,uint32_t start,uint32_t len,uint32_t attrs)63 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 */
64 {
65 uint32_t proposedStart, proposedLen, lenVal = 1;
66 uint64_t intState;
67
68 /* expand until it works */
69 do {
70 /* special case 4GB region */
71 if (lenVal == 32) {
72 proposedStart = 0;
73 break;
74 }
75
76 proposedStart = start &~ ((1ULL << lenVal) - 1);
77 proposedLen = start + len - proposedStart;
78 if (proposedLen < 32)
79 proposedLen = 32;
80 lenVal = (proposedLen & (proposedLen - 1)) ? 32 - __builtin_clz(proposedLen) : 31 - __builtin_clz(proposedLen);
81
82 } while (proposedStart & ((1ULL << lenVal) - 1));
83
84 intState = cpuIntsOff();
85 asm volatile("dsb\nisb");
86
87 MPU->RNR = regionNo;
88 MPU->RASR = 0; /* disable region before changing it */
89 MPU->RBAR = proposedStart;
90 MPU->RASR = MPU_SRD_BITS | MPU_BIT_ENABLE | attrs | (lenVal << 1);
91
92 asm volatile("dsb\nisb");
93 cpuIntsRestore(intState);
94 }
95
mpuCfgRom(bool allowSvcWrite)96 static void mpuCfgRom(bool allowSvcWrite)
97 {
98 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));
99 }
100
mpuCfgRam(bool allowSvcExecute)101 static void mpuCfgRam(bool allowSvcExecute)
102 {
103 mpuRegionCfg(MPU_REG_RAM, (uint32_t)&__ram_start, __ram_end - __ram_start, MPU_TYPE_MEMORY | MPU_RW | (allowSvcExecute ? 0 : MPU_BIT_XN));
104 }
105
106
mpuStart(void)107 void mpuStart(void)
108 {
109 MPU->CTRL = 0x07; //MPU on, even during faults, supervisor default: allow, user default: default deny
110
111 mpuCfgRom(false);
112 mpuCfgRam(false);
113 mpuRegionCfg(MPU_REG_NULL_PAGE, 0, 4096, MPU_TYPE_MEMORY | MPU_NA | MPU_BIT_XN);
114 }
115
mpuAllowRamExecution(bool allowSvcExecute)116 void mpuAllowRamExecution(bool allowSvcExecute)
117 {
118 mpuCfgRam(allowSvcExecute);
119 }
120
mpuAllowRomWrite(bool allowSvcWrite)121 void mpuAllowRomWrite(bool allowSvcWrite)
122 {
123 mpuCfgRom(allowSvcWrite);
124 }
125
126