1 /*
2 * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3 * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this list of
9 * conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12 * of conditions and the following disclaimer in the documentation and/or other materials
13 * provided with the distribution.
14 *
15 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16 * to endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31 #include "los_mpu.h"
32 #include "los_config.h"
33 #include "los_context.h"
34
35 #if (LOSCFG_MPU_ENABLE == 1)
36
37 #define SIZE_4G_BYTE 0x100000000
38 #define MPU_MAX_REGION_NUM 8
39
40 STATIC UINT8 g_regionNumBeUsed[MPU_MAX_REGION_NUM] = {0};
41
42 typedef enum {
43 MPU_AP_FORBID_USER_FORBID = 0x0, /* Privileged:No access Unprivileged:No access */
44 MPU_AP_RW_USER_FORBID = 0x1, /* Privileged:Read/Write Unprivileged:No access */
45 MPU_AP_RW_USER_RO = 0x2, /* Privileged:Read/Write Unprivileged:Read-only */
46 MPU_AP_RW_USER_RW = 0x3, /* Privileged:Read/Write Unprivileged:Read/Write */
47 MPU_AP_NA_USER_NA = 0x4, /* Privileged:UNPREDICTABLE Unprivileged:UNPREDICTABLE */
48 MPU_AP_RO_USER_FORBID = 0x5, /* Privileged:Read-only Unprivileged:No access */
49 MPU_AP_RO_USER_RO = 0x6, /* Privileged:Read-only Unprivileged:Read-only */
50 } MpuApConfig;
51
ArchMpuEnable(UINT32 defaultRegionEnable)52 VOID ArchMpuEnable(UINT32 defaultRegionEnable)
53 {
54 UINT32 intSave = ArchIntLock();
55 MPU->CTRL = (MPU_CTRL_ENABLE_Msk | ((defaultRegionEnable << MPU_CTRL_PRIVDEFENA_Pos) & MPU_CTRL_PRIVDEFENA_Msk));
56 SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
57 __DSB();
58 __ISB();
59 ArchIntRestore(intSave);
60 }
ArchMpuDisable(VOID)61 VOID ArchMpuDisable(VOID)
62 {
63 UINT32 intSave = ArchIntLock();
64 MPU->CTRL = 0;
65 __DSB();
66 __ISB();
67 ArchIntRestore(intSave);
68 }
69
HalMpuRASRAddMemAttr(MPU_CFG_PARA * para,UINT32 * RASR)70 STATIC VOID HalMpuRASRAddMemAttr(MPU_CFG_PARA *para, UINT32 *RASR)
71 {
72 BOOL cachable = 0;
73 BOOL buffable = 0;
74 switch (para->memType) {
75 case MPU_MEM_ON_CHIP_ROM:
76 case MPU_MEM_ON_CHIP_RAM:
77 cachable = 1;
78 buffable = 0;
79 break;
80 case MPU_MEM_XIP_PSRAM:
81 cachable = 1;
82 buffable = 1;
83 break;
84 case MPU_MEM_XIP_NOR_FLASH:
85 cachable = 0;
86 buffable = 1;
87 break;
88 default:
89 break;
90 }
91 (*RASR) |= ((cachable << MPU_RASR_C_Pos) | (buffable << MPU_RASR_B_Pos));
92 }
93
HalMpuEncodeSize(UINT64 size)94 STATIC UINT32 HalMpuEncodeSize(UINT64 size)
95 {
96 UINT32 encodeSize = 0;
97 if (size > SIZE_4G_BYTE) {
98 return 0;
99 }
100 if ((size & 0x1F) != 0) { /* size should aligned to 32 byte at least. */
101 return 0;
102 }
103 size = (size >> 2);
104 while (size != 0) {
105 if (((size & 1) != 0) && ((size & 0xFFFFFFFE) != 0)) { /* size != 2^x (5 <= x <= 32) 128B - 4GB */
106 return 0;
107 }
108 size = (size >> 1);
109 encodeSize++;
110 }
111 return encodeSize;
112 }
113
HalMpuEncodeAP(MpuAccessPermission permission)114 STATIC UINT32 HalMpuEncodeAP(MpuAccessPermission permission)
115 {
116 UINT32 ap;
117 switch (permission) {
118 case MPU_RW_BY_PRIVILEGED_ONLY:
119 ap = MPU_AP_RW_USER_FORBID;
120 break;
121 case MPU_RW_ANY:
122 ap = MPU_AP_RW_USER_RW;
123 break;
124 case MPU_RO_BY_PRIVILEGED_ONLY:
125 ap = MPU_AP_RO_USER_FORBID;
126 break;
127 case MPU_RO_ANY:
128 ap = MPU_AP_RO_USER_RO;
129 break;
130 default:
131 ap = MPU_AP_RW_USER_RW;
132 break;
133 }
134 return ap;
135 }
136
HalMpuGetRASR(UINT32 encodeSize,MPU_CFG_PARA * para)137 STATIC UINT32 HalMpuGetRASR(UINT32 encodeSize, MPU_CFG_PARA *para)
138 {
139 UINT32 RASR;
140 UINT32 ap;
141 ap = HalMpuEncodeAP(para->permission);
142 RASR = MPU_RASR_ENABLE_Msk;
143 RASR |= ((encodeSize << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk);
144 RASR |= ((ap << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | ((para->executable << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) |
145 ((para->shareability << MPU_RASR_S_Pos) & MPU_RASR_S_Msk);
146 HalMpuRASRAddMemAttr(para, &RASR);
147 return RASR;
148 }
149
ArchMpuSetRegion(UINT32 regionId,MPU_CFG_PARA * para)150 UINT32 ArchMpuSetRegion(UINT32 regionId, MPU_CFG_PARA *para)
151 {
152 UINT32 RASR;
153 UINT32 RBAR;
154 UINT32 RNR;
155 UINT32 encodeSize;
156 UINT32 intSave;
157 UINT64 size;
158
159 if ((regionId >= MPU_MAX_REGION_NUM) || (para == NULL)) {
160 return LOS_NOK;
161 }
162
163 if ((MPU_TYPE_DREGION_Msk & MPU->TYPE) == 0) {
164 return LOS_NOK;
165 }
166
167 RNR = regionId;
168 encodeSize = HalMpuEncodeSize(para->size);
169 if (encodeSize == 0) {
170 return LOS_NOK;
171 }
172 size = para->size - 1; /* size aligned after encode check */
173 if ((para->baseAddr & size) != 0) { /* base addr should aligned to region size */
174 return LOS_NOK;
175 }
176 RBAR = para->baseAddr & MPU_RBAR_ADDR_Msk;
177 RASR = HalMpuGetRASR(encodeSize, para);
178 intSave = ArchIntLock();
179 if (g_regionNumBeUsed[regionId]) {
180 ArchIntRestore(intSave);
181 return LOS_NOK;
182 }
183 MPU->RNR = RNR;
184 MPU->RBAR = RBAR;
185 MPU->RASR = RASR;
186 __DSB();
187 __ISB();
188 g_regionNumBeUsed[regionId] = 1; /* Set mpu region used flag */
189 ArchIntRestore(intSave);
190 return LOS_OK;
191 }
192
ArchMpuDisableRegion(UINT32 regionId)193 UINT32 ArchMpuDisableRegion(UINT32 regionId)
194 {
195 volatile UINT32 type;
196 UINT32 intSave;
197
198 if (regionId >= MPU_MAX_REGION_NUM) {
199 return LOS_NOK;
200 }
201
202 intSave = ArchIntLock();
203 if (!g_regionNumBeUsed[regionId]) {
204 ArchIntRestore(intSave);
205 return LOS_NOK;
206 }
207
208 type = MPU->TYPE;
209 if ((MPU_TYPE_DREGION_Msk & type) != 0) {
210 MPU->RNR = regionId;
211 MPU->RASR = 0;
212 __DSB();
213 __ISB();
214 }
215 g_regionNumBeUsed[regionId] = 0; /* clear mpu region used flag */
216 ArchIntRestore(intSave);
217 return LOS_OK;
218 }
219
ArchMpuUnusedRegionGet(VOID)220 INT32 ArchMpuUnusedRegionGet(VOID)
221 {
222 INT32 id;
223 UINT32 intSave = ArchIntLock();
224 for (id = 0; id < MPU_MAX_REGION_NUM; id++) {
225 if (!g_regionNumBeUsed[id]) {
226 break;
227 }
228 }
229 ArchIntRestore(intSave);
230
231 if (id == MPU_MAX_REGION_NUM) {
232 return -1;
233 } else {
234 return id;
235 }
236 }
237 #endif
238