114986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi/*
214986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * Copyright (C) 2016 The Android Open Source Project
314986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi *
414986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * Licensed under the Apache License, Version 2.0 (the "License");
514986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * you may not use this file except in compliance with the License.
614986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * You may obtain a copy of the License at
714986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi *
814986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi *      http://www.apache.org/licenses/LICENSE-2.0
914986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi *
1014986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * Unless required by applicable law or agreed to in writing, software
1114986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * distributed under the License is distributed on an "AS IS" BASIS,
1214986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1314986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * See the License for the specific language governing permissions and
1414986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi * limitations under the License.
1514986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi */
1614986b090cf259d3d9e6762520dfc276e30de911Ashutosh Joshi
175a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#include <stdbool.h>
185a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#include <stdint.h>
19bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov
20bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov#include <bl.h>
21659f9df90838b00bff8fd94985c357db57d1c8b5Dmitry Grinberg#include <cpu.h>
22bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov#include <mpu.h>
23bf34a2b6e59688feefe63537e6d378b9de71fb8cAlexey Polyudov#include <platform.h>
245a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
255a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinbergstruct CortexMpu {
265a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    volatile uint32_t CTRL;
275a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    volatile uint32_t RNR;
285a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    volatile uint32_t RBAR;
295a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    volatile uint32_t RASR;
305a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg};
315a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
325a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU ((struct CortexMpu*)0xE000ED94UL)
335a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
34c4a6f4ca4298e1af237cc9b990aeadb21ec9ad63Dmitry Grinberg#define MPU_REG_ROM          0
35c4a6f4ca4298e1af237cc9b990aeadb21ec9ad63Dmitry Grinberg#define MPU_REG_RAM          1
36c4a6f4ca4298e1af237cc9b990aeadb21ec9ad63Dmitry Grinberg#define MPU_REG_NULL_PAGE    2
375a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
385a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
395a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg/* region type */
405a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU_TYPE_DEVICE (0x10UL << 16)
415a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU_TYPE_MEMORY (0x0FUL << 16)
425a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
435a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg/* region execute priviledges */
445a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU_BIT_XN      (1UL << 28) /* no execute */
455a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
46c4a6f4ca4298e1af237cc9b990aeadb21ec9ad63Dmitry Grinberg/* region access priviledges */
475a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU_NA          (0UL << 24) /* S: no access   U: no access */
485a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU_U_NA_S_RW   (1UL << 24) /* S: RW          U: no access */
495a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU_U_RO_S_RW   (2UL << 24) /* S: RW          U: RO        */
505a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU_RW          (3UL << 24) /* S: RW          U: RW        */
515a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU_U_NA_S_RO   (5UL << 24) /* S: RO          U: no access */
525a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU_U_RO_S_RO   (6UL << 24) /* S: RO          U: RO        */
535a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
545a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg/* subregion mask (not used so all ones) */
555a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU_SRD_BITS    0xFF00UL
565a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg#define MPU_BIT_ENABLE  1UL
575a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
585a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg/* these define rom */
595a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinbergextern uint8_t __shared_end[];
605a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinbergextern uint8_t __ram_start[];
615a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinbergextern uint8_t __ram_end[];
625a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
635a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinbergstatic 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 */
645a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg{
655a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    uint32_t proposedStart, proposedLen, lenVal = 1;
665a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    uint64_t intState;
675a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
685a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    /* expand until it works */
695a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    do {
705a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg        /* special case 4GB region */
715a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg        if (lenVal == 32) {
725a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg            proposedStart = 0;
735a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg            break;
745a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg        }
755a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
765a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg        proposedStart = start &~ ((1ULL << lenVal) - 1);
775a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg        proposedLen = start + len - proposedStart;
785a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg        if (proposedLen < 32)
795a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg            proposedLen = 32;
805a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg        lenVal = (proposedLen & (proposedLen - 1)) ? 32 - __builtin_clz(proposedLen) : 31 - __builtin_clz(proposedLen);
815a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
825a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    } while (proposedStart & ((1ULL << lenVal) - 1));
835a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
84659f9df90838b00bff8fd94985c357db57d1c8b5Dmitry Grinberg    intState = cpuIntsOff();
855a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    asm volatile("dsb\nisb");
865a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
875a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    MPU->RNR = regionNo;
885a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    MPU->RASR = 0; /* disable region before changing it */
895a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    MPU->RBAR = proposedStart;
905a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    MPU->RASR = MPU_SRD_BITS | MPU_BIT_ENABLE | attrs | (lenVal << 1);
915a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
925a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    asm volatile("dsb\nisb");
93659f9df90838b00bff8fd94985c357db57d1c8b5Dmitry Grinberg    cpuIntsRestore(intState);
945a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg}
955a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
965a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinbergstatic void mpuCfgRom(bool allowSvcWrite)
975a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg{
98c4a6f4ca4298e1af237cc9b990aeadb21ec9ad63Dmitry Grinberg    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));
995a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg}
1005a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
1015a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinbergstatic void mpuCfgRam(bool allowSvcExecute)
1025a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg{
103c4a6f4ca4298e1af237cc9b990aeadb21ec9ad63Dmitry Grinberg    mpuRegionCfg(MPU_REG_RAM, (uint32_t)&__ram_start, __ram_end - __ram_start, MPU_TYPE_MEMORY | MPU_RW | (allowSvcExecute ? 0 : MPU_BIT_XN));
1045a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg}
1055a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
1065a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
1075a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinbergvoid mpuStart(void)
1085a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg{
109c4a6f4ca4298e1af237cc9b990aeadb21ec9ad63Dmitry Grinberg    MPU->CTRL = 0x07; //MPU on, even during faults, supervisor default: allow, user default: default deny
1105a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
1115a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    mpuCfgRom(false);
1125a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    mpuCfgRam(false);
113c4a6f4ca4298e1af237cc9b990aeadb21ec9ad63Dmitry Grinberg    mpuRegionCfg(MPU_REG_NULL_PAGE, 0, 4096, MPU_TYPE_MEMORY | MPU_NA | MPU_BIT_XN);
1145a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg}
1155a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
1165a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinbergvoid mpuAllowRamExecution(bool allowSvcExecute)
1175a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg{
1185a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    mpuCfgRam(allowSvcExecute);
1195a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg}
1205a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
1215a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinbergvoid mpuAllowRomWrite(bool allowSvcWrite)
1225a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg{
1235a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg    mpuCfgRom(allowSvcWrite);
1245a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg}
1255a17a7a8ed94b23a59d6bac6ff6d94e5ca976205Dmitry Grinberg
126