/* * Copyright (c) 2019 Actions Semiconductor Co., Ltd * * SPDX-License-Identifier: Apache-2.0 */ /** * @file arm mpu */ #include #include #include #include #include #include /* Global MAIR configurations */ #define MPU_MAIR_INDEX_NC 0 #define MPU_RBAR_AP_Pos 1U /* Privileged Read Write, Unprivileged Read Write */ #define P_RW_U_RW 0x1 #define P_RW_U_RW_Msk (P_RW_U_RW << MPU_RBAR_AP_Pos) /* Privileged Read Only, Unprivileged Read Only */ #define P_RO_U_RO 0x3 #define P_RO_U_RO_Msk (P_RO_U_RO << MPU_RBAR_AP_Pos) #define MPU_RBAR_SH_Pos 3U #define INNER_SHAREABLE 0x3 #define INNER_SHAREABLE_Msk (INNER_SHAREABLE << MPU_RBAR_SH_Pos) /* Attribute flag for not-allowing execution (eXecute Never) */ #define NOT_EXEC 0x01 static const char *mpu_attr_str[3] = { "NO", "RW", "RO"}; /*MPU set, mem_base= must align to size , n >= 5 (32-2GB),*/ void act_mpu_set(uint32_t chan, uint32_t mem_base, uint32_t size, uint32_t attr) { uint32_t mpu_base, mpu_end, mpu_attr; uint32_t num_region ; num_region = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; if(chan >= num_region){ printk("mpu set over max region:%d >= %d\n", chan, num_region); return; } if(!(MPU->CTRL & MPU_CTRL_ENABLE_Msk)){ // Memory Attribute Indirection Register 0 MPU->MAIR0 = ((0x44 & MPU_MAIR0_Attr0_Msk) | // Normal memory, Inner Non-cacheable, Outer Non-cacheable (0x44 << MPU_MAIR0_Attr1_Pos) | // Normal memory, Inner Non-cacheable, Outer Non-cacheable (0x44 << MPU_MAIR0_Attr2_Pos) | // Normal memory, Inner Non-cacheable, Outer Non-cacheable (0x44 << MPU_MAIR0_Attr3_Pos)); // Normal memory, Inner Non-cacheable, Outer Non-cacheable MPU->CTRL = MPU_CTRL_ENABLE_Msk | MPU_CTRL_PRIVDEFENA_Msk; } mpu_base = (mem_base+0x1f) & (~0x1f); // 32B align mpu_end = ((mem_base+size) & (~0x1f))-1; if(attr == MPU_ATTR_NO){ mpu_attr = P_RO_U_RO_Msk | INNER_SHAREABLE_Msk | NOT_EXEC; //no exe, ro }else if(attr == MPU_ATTR_RW){ mpu_attr = P_RW_U_RW_Msk | INNER_SHAREABLE_Msk ; // exe, rw } else { mpu_attr = P_RO_U_RO_Msk | INNER_SHAREABLE_Msk ; // exe, ro } printk("mpu %d(%d): 0x%x-0x%x, set=0x%x-0x%x,attr=%s\n", chan , num_region, mpu_base, mpu_end, mem_base, mem_base+size, mpu_attr_str[attr]); MPU->RNR = chan; // Base address MPU->RBAR = (mpu_base | mpu_attr); // Limit register MPU->RLAR = ((mpu_end & MPU_RLAR_LIMIT_Msk) | // Size (MPU_MAIR_INDEX_NC << MPU_RLAR_AttrIndx_Pos) | // AttrIndex - 0 (0x1 << MPU_RLAR_EN_Pos)); // Enable - On } void act_mpu_unset(uint32_t chan) { uint32_t num_region ; num_region = (MPU->TYPE & MPU_TYPE_DREGION_Msk) >> MPU_TYPE_DREGION_Pos; if(chan >= num_region){ printk("mpu unset over max region:%d >= %d\n", chan, num_region); return; } MPU->RNR = chan; MPU->RBAR = 0; MPU->RLAR = 0; printk("mpu %d unset\n", chan); } void arm_mpu_protect_init(void) { /* protect rom section */ act_mpu_set(MPU_CHAN_ROM, 0x0, 0x10000, MPU_ATTR_RO); /* protect flash cache all address section */ act_mpu_set(MPU_CHAN_CODE, (CONFIG_FLASH_BASE_ADDRESS + CONFIG_FLASH_LOAD_OFFSET), 0x1000000, MPU_ATTR_RO); #if defined(CONFIG_ARCH_HAS_RAMFUNC_SUPPORT) act_mpu_set(MPU_CHAN_RAMFUC, (uint32_t)&__ramfunc_start, (uint32_t)&__ramfunc_size, MPU_ATTR_RO); #endif /* CONFIG_ARCH_HAS_RAMFUNC_SUPPORT */ } #define CPU_TRACE_RAM_ADDR 0x31000000 #define CPU_TRACE_RAM_MAXLEN 1024 static void trace_dump_str(unsigned int *buf, unsigned int len) { int i; for(i = 0; i < len/4; i++) { if((i&0x7)==0){ printk("%08x:",CPU_TRACE_RAM_ADDR+i*4); } printk("%08x ", buf[i]); if( (i&0x7)==7 ) printk("\n"); } printk("\n"); } void cpu_trace_enable(int enable) { if(enable){ sys_write32(0 , 0xe0043004); memset((void*)CPU_TRACE_RAM_ADDR, 0, CPU_TRACE_RAM_MAXLEN); sys_write32(0 , 0xe0043000); sys_write32((1<<31)|0xf , 0xe0043004); }else{ sys_write32(0 , 0xe0043004); } } static int act_mpu_init(const struct device *arg) { //unsigned int val = 0; ARG_UNUSED(arg); printk("arm mpu init\n"); arm_mpu_protect_init(); //soc_pstore_get(SOC_PSTORE_TAG_SYS_PANIC,&val); //if(val){ printk("arm trace dump:\n"); trace_dump_str((unsigned int *)CPU_TRACE_RAM_ADDR, CPU_TRACE_RAM_MAXLEN); //} cpu_trace_enable(1); return 0; } SYS_INIT(act_mpu_init, APPLICATION, 20);