1 /*
2  * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3  */
4 
5 #if AOS_COMP_DEBUG
6 
7 #include <stdio.h>
8 #include "panic_mpu.h"
9 #include "k_compiler.h"
10 #include "k_api.h"
11 
12 typedef struct {
13     unsigned long start;
14     unsigned long size;
15     unsigned long mpusize;
16 } mem_region_t;
17 
18 static void mpu_enable(void);
19 static void mpu_disable(void);
20 static void mpu_config_region(MPU_Region_Init_t *init);
21 static unsigned int size_to_mpusize(unsigned int size);
22 
23 /*
24  * Func: mpu is valid in mcu
25  * IN  : none
26  * Out : 0 -- valid; 1 -- invalid
27  * */
mpu_is_valid(void)28 static unsigned int mpu_is_valid(void)
29 {
30     return ((MPU->type) & MPU_TYPE_DREGION_MASK == 0) ? 1: 0;
31 }
32 
mpu_enable(void)33 static void mpu_enable(void)
34 {
35     MPU->ctrl = MPU_CTRL_ENABLE_MASK | MPU_CTRL_PRIVDEFENA_MASK;
36 
37     /* Enable memory manage fault */
38     *(SHCSR_M) |= (1<<16);
39 
40     OS_DSB();
41     OS_ISB();
42     OS_DMB();
43 }
44 
mpu_disable(void)45 static void mpu_disable(void)
46 {
47     MPU->ctrl = 0U;
48 
49     OS_DSB();
50     OS_ISB();
51     OS_DMB();
52 }
53 
enable_region(mem_region_t * region,int rng_no,int subregion_disable,int ext_type,int access_permission,int disable_exec,int shareable,int cacheable,int bufferable)54 static void enable_region(mem_region_t *region, int rng_no,
55                           int subregion_disable, int ext_type,
56                           int access_permission, int disable_exec,
57                           int shareable, int cacheable, int bufferable)
58 {
59     MPU_Region_Init_t init;
60 
61     init.range_no          = rng_no;
62     init.base_addr         = region->start;
63     init.size              = region->mpusize;
64     init.subregion_disable = subregion_disable;
65     init.ext_type          = ext_type;
66     init.access_permission = access_permission;
67     init.disable_exec      = disable_exec;
68     init.shareable         = shareable;
69     init.cacheable         = cacheable;
70     init.bufferable        = bufferable;
71     init.enable            = 1;
72 
73     mpu_config_region(&init);
74 }
75 
76 
mpu_config_region(MPU_Region_Init_t * init)77 static void mpu_config_region(MPU_Region_Init_t *init)
78 {
79     MPU->rnr = init->range_no;
80 
81     if (init->enable) {
82         MPU->rbar = init->base_addr;
83         MPU->rasr = (init->disable_exec << MPU_RASR_XN_OFFSET
84                     | init->access_permission << MPU_RASR_AP_OFFSET
85                     | init->ext_type << MPU_RASR_TEX_OFFSET
86                     | init->shareable << MPU_RASR_S_OFFSET
87                     | init->cacheable << MPU_RASR_C_OFFSET
88                     | init->bufferable << MPU_RASR_B_OFFSET
89                     | init->subregion_disable << MPU_RASR_SRD_OFFSET
90                     | init->size << MPU_RASR_SIZE_OFFSET
91                     | init->enable << MPU_RASR_ENABLE_OFFSET);
92     } else {
93         MPU->rbar = 0;
94         MPU->rasr = 0;
95     }
96 
97     OS_DSB();
98     OS_ISB();
99     OS_DMB();
100 }
101 
size_to_mpusize(unsigned int size)102 static unsigned int size_to_mpusize(unsigned int size)
103 {
104     switch (size) {
105         case 0x20:        return MPU_REGION_SIZE_32B;
106         case 0x40:        return MPU_REGION_SIZE_64B;
107         case 0x80:        return MPU_REGION_SIZE_128B;
108         case 0x100:       return MPU_REGION_SIZE_256B;
109         case 0x200:       return MPU_REGION_SIZE_512B;
110         case 0x400:       return MPU_REGION_SIZE_1KB;
111         case 0x800:       return MPU_REGION_SIZE_2KB;
112         case 0x1000:      return MPU_REGION_SIZE_4KB;
113         case 0x2000:      return MPU_REGION_SIZE_8KB;
114         case 0x4000:      return MPU_REGION_SIZE_16KB;
115         case 0x8000:      return MPU_REGION_SIZE_32KB;
116         case 0x10000:     return MPU_REGION_SIZE_64KB;
117         case 0x20000:     return MPU_REGION_SIZE_128KB;
118         case 0x40000:     return MPU_REGION_SIZE_256KB;
119         case 0x80000:     return MPU_REGION_SIZE_512KB;
120         case 0x100000:    return MPU_REGION_SIZE_1MB;
121         case 0x200000:    return MPU_REGION_SIZE_2MB;
122         case 0x400000:    return MPU_REGION_SIZE_4MB;
123         case 0x800000:    return MPU_REGION_SIZE_8MB;
124         case 0x1000000:   return MPU_REGION_SIZE_16MB;
125         case 0x2000000:   return MPU_REGION_SIZE_32MB;
126         case 0x4000000:   return MPU_REGION_SIZE_64MB;
127         case 0x8000000:   return MPU_REGION_SIZE_128MB;
128         case 0x10000000:  return MPU_REGION_SIZE_256MB;
129         case 0x20000000:  return MPU_REGION_SIZE_512MB;
130         case 0x40000000:  return MPU_REGION_SIZE_1GB;
131         case 0x80000000:  return MPU_REGION_SIZE_2GB;
132 
133         default: return 0;
134     }
135 }
136 
mpu_set(unsigned long addr,unsigned long size,unsigned int mode)137 static void mpu_set(unsigned long addr, unsigned long size, unsigned int mode)
138 {
139     mem_region_t region;
140 
141     region.start   = addr;
142     region.size    = size;
143     region.mpusize = size_to_mpusize(region.size);
144 
145     mpu_disable();
146 
147     enable_region(&region, 0, 0, 0, mode, 0, 0, 1, 1);
148 
149     mpu_enable();
150 }
151 
mpu_check(unsigned long addr,unsigned long size)152 static unsigned int mpu_check(unsigned long addr, unsigned long size)
153 {
154     if ((size < 0x20) || (size > 0x80000000)) {
155         printf("mpu region size error\r\n");
156         return 1;
157     }
158 
159     if (mpu_is_valid() != 0) {
160         printf("error:no mpu in mcu\r\n");
161         return 1;
162     }
163 
164     return 0;
165 }
166 
167 /**
168  * set mpu region for memory unauthorized access check
169  *
170  * @param[in]  addr_start   monitor start addr
171  * @param[in]  addr_size    monitor size
172  * @param[in]  mode         prohibit access (0) or read only(>0)
173  */
debug_memory_access_err_check(unsigned long addr_start,unsigned long addr_size,unsigned int mode)174 void debug_memory_access_err_check(unsigned long addr_start, unsigned long addr_size, unsigned int mode)
175 {
176     unsigned int mpu_region_type;
177 
178     if (mpu_check(addr_start, addr_size) != 0)
179         return;
180 
181     if ((addr_start % addr_size) != 0)
182         addr_start = (addr_start + (addr_size - 1)) & ~(addr_size - 1);
183 
184     if (mode > 0) {
185         mpu_region_type = MPU_AP_RO_NA;
186     } else
187         mpu_region_type = MPU_AP_NA_NA;
188 
189     mpu_set(addr_start, addr_size, mpu_region_type);
190     printf("mpu addr: 0x%x\n", addr_start);
191 }
192 
debug_task_stack_ovf_check(char * task_name)193 void debug_task_stack_ovf_check(char *task_name)
194 {
195     int         ret;
196     ktask_t     *task;
197     cpu_stack_t *task_stack_base;
198 
199     if (task_name == NULL) {
200         printf("error: task name invalid\r\n");
201         return;
202     }
203 
204     task = krhino_task_find(task_name);
205     if (task == NULL) {
206         printf("error: task do not exist\r\n");
207         return;
208     }
209 
210     task_stack_base = task->task_stack_base;
211     if (task_stack_base == NULL) {
212         printf("error: task_stack_base err\r\n");
213         return;
214     }
215 
216     debug_memory_access_err_check((unsigned long)task_stack_base, 0x20, 1);
217 }
218 
debug_check_mem_access_disable(void)219 void debug_check_mem_access_disable(void)
220 {
221     mpu_disable();
222 }
223 
224 #endif
225