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 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 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 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 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 116 void mpuAllowRamExecution(bool allowSvcExecute) 117 { 118 mpuCfgRam(allowSvcExecute); 119 } 120 121 void mpuAllowRomWrite(bool allowSvcWrite) 122 { 123 mpuCfgRom(allowSvcWrite); 124 } 125 126