xref: /nrf52832-nimble/rt-thread/libcpu/arm/armv6/mmu.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1 /*
2  * Copyright (c) 2006-2018, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  */
9 
10 #include "mmu.h"
11 
12 #ifdef __CC_ARM
13 void mmu_setttbase(rt_uint32_t i)
14 {
15 	register rt_uint32_t value;
16 
17 	/* Invalidates all TLBs.Domain access is selected as
18 	 * client by configuring domain access register,
19 	 * in that case access controlled by permission value
20 	 * set by page table entry
21 	 */
22 	value = 0;
23 	__asm volatile
24 	{
25 		mcr p15, 0, value, c8, c7, 0
26 	}
27 
28 	value = 0x55555555;
29 	__asm volatile
30 	{
31 		mcr p15, 0, value, c3, c0, 0
32 			mcr p15, 0, i, c2, c0, 0
33 	}
34 }
35 
36 void mmu_set_domain(rt_uint32_t i)
37 {
38 	__asm volatile
39 	{
40 		mcr p15,0, i, c3, c0,  0
41 	}
42 }
43 
44 void mmu_enable()
45 {
46 	register rt_uint32_t value;
47 
48 	__asm volatile
49 	{
50 		mrc p15, 0, value, c1, c0, 0
51 			orr value, value, #0x01
52 			mcr p15, 0, value, c1, c0, 0
53 	}
54 }
55 
56 void mmu_disable()
57 {
58 	register rt_uint32_t value;
59 
60 	__asm volatile
61 	{
62 		mrc p15, 0, value, c1, c0, 0
63 			bic value, value, #0x01
64 			mcr p15, 0, value, c1, c0, 0
65 	}
66 }
67 
68 void mmu_enable_icache()
69 {
70 	register rt_uint32_t value;
71 
72 	__asm volatile
73 	{
74 		mrc p15, 0, value, c1, c0, 0
75 			orr value, value, #0x1000
76 			mcr p15, 0, value, c1, c0, 0
77 	}
78 }
79 
80 void mmu_enable_dcache()
81 {
82 	register rt_uint32_t value;
83 
84 	__asm volatile
85 	{
86 		mrc p15, 0, value, c1, c0, 0
87 			orr value, value, #0x04
88 			mcr p15, 0, value, c1, c0, 0
89 	}
90 }
91 
92 void mmu_disable_icache()
93 {
94 	register rt_uint32_t value;
95 
96 	__asm volatile
97 	{
98 		mrc p15, 0, value, c1, c0, 0
99 			bic value, value, #0x1000
100 			mcr p15, 0, value, c1, c0, 0
101 	}
102 }
103 
104 void mmu_disable_dcache()
105 {
106 	register rt_uint32_t value;
107 
108 	__asm volatile
109 	{
110 		mrc p15, 0, value, c1, c0, 0
111 			bic value, value, #0x04
112 			mcr p15, 0, value, c1, c0, 0
113 	}
114 }
115 
116 void mmu_enable_alignfault()
117 {
118 	register rt_uint32_t value;
119 
120 	__asm volatile
121 	{
122 		mrc p15, 0, value, c1, c0, 0
123 			orr value, value, #0x02
124 			mcr p15, 0, value, c1, c0, 0
125 	}
126 }
127 
128 void mmu_disable_alignfault()
129 {
130 	register rt_uint32_t value;
131 
132 	__asm volatile
133 	{
134 		mrc p15, 0, value, c1, c0, 0
135 			bic value, value, #0x02
136 			mcr p15, 0, value, c1, c0, 0
137 	}
138 }
139 
140 void mmu_clean_invalidated_cache_index(int index)
141 {
142 	__asm volatile
143 	{
144 		mcr p15, 0, index, c7, c14, 2
145 	}
146 }
147 
148 void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
149 {
150 	unsigned int ptr;
151 
152 	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
153 
154 	while(ptr < buffer + size)
155 	{
156 		__asm volatile
157 		{
158 			MCR p15, 0, ptr, c7, c14, 1
159 		}
160 		ptr += CACHE_LINE_SIZE;
161 	}
162 }
163 
164 void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
165 {
166 	unsigned int ptr;
167 
168 	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
169 
170 	while (ptr < buffer + size)
171 	{
172 		__asm volatile
173 		{
174 			MCR p15, 0, ptr, c7, c10, 1
175 		}
176 		ptr += CACHE_LINE_SIZE;
177 	}
178 }
179 
180 void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
181 {
182 	unsigned int ptr;
183 
184 	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
185 
186 	while (ptr < buffer + size)
187 	{
188 		__asm volatile
189 		{
190 			MCR p15, 0, ptr, c7, c6, 1
191 		}
192 		ptr += CACHE_LINE_SIZE;
193 	}
194 }
195 
196 void mmu_invalidate_tlb()
197 {
198 	register rt_uint32_t value;
199 
200 	value = 0;
201 	__asm volatile
202 	{
203 		mcr p15, 0, value, c8, c7, 0
204 	}
205 }
206 
207 void mmu_invalidate_icache()
208 {
209 	register rt_uint32_t value;
210 
211 	value = 0;
212 
213 	__asm volatile
214 	{
215 		mcr p15, 0, value, c7, c5, 0
216 	}
217 }
218 
219 
220 void mmu_invalidate_dcache_all()
221 {
222 	register rt_uint32_t value;
223 
224 	value = 0;
225 
226 	__asm volatile
227 	{
228 		mcr p15, 0, value, c7, c6, 0
229 	}
230 }
231 #elif defined(__GNUC__)
232 void mmu_setttbase(register rt_uint32_t i)
233 {
234 	register rt_uint32_t value;
235 
236 	/* Invalidates all TLBs.Domain access is selected as
237 	 * client by configuring domain access register,
238 	 * in that case access controlled by permission value
239 	 * set by page table entry
240 	 */
241 	value = 0;
242 	asm volatile ("mcr p15, 0, %0, c8, c7, 0"::"r"(value));
243 
244 	value = 0x55555555;
245 	asm volatile ("mcr p15, 0, %0, c3, c0, 0"::"r"(value));
246 	asm volatile ("mcr p15, 0, %0, c2, c0, 0"::"r"(i));
247 }
248 
249 void mmu_set_domain(register rt_uint32_t i)
250 {
251 	asm volatile ("mcr p15,0, %0, c3, c0,  0": :"r" (i));
252 }
253 
254 void mmu_enable()
255 {
256 	register rt_uint32_t i;
257 
258 	/* read control register */
259 	asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
260 
261 	i |= 0x1;
262 	/* Enables the extended page tables to be configured for
263 	   the hardware page translation mechanism, Subpage AP bits disabled */
264 	i |= (1 << 23); /* support for ARMv6 MMU features */
265 	i |= (1 << 13); /* High exception vectors selected, address range = 0xFFFF0000-0xFFFF001C */
266 
267 	/* write back to control register */
268 	asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
269 }
270 
271 void mmu_disable()
272 {
273 	register rt_uint32_t i;
274 
275 	/* read control register */
276 	asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
277 
278 	i &= ~0x1;
279 
280 	/* write back to control register */
281 	asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
282 }
283 
284 void mmu_enable_icache()
285 {
286 	register rt_uint32_t i;
287 
288 	/* read control register */
289 	asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
290 
291 	i |= (1 << 12);
292 
293 	/* write back to control register */
294 	asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
295 }
296 
297 void mmu_enable_dcache()
298 {
299 	register rt_uint32_t i;
300 
301 	/* read control register */
302 	asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
303 
304 	i |= (1 << 2);
305 
306 	/* write back to control register */
307 	asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
308 }
309 
310 void mmu_disable_icache()
311 {
312 	register rt_uint32_t i;
313 
314 	/* read control register */
315 	asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
316 
317 	i &= ~(1 << 12);
318 
319 	/* write back to control register */
320 	asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
321 }
322 
323 void mmu_disable_dcache()
324 {
325 	register rt_uint32_t i;
326 
327 	/* read control register */
328 	asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
329 
330 	i &= ~(1 << 2);
331 
332 	/* write back to control register */
333 	asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
334 }
335 
336 void mmu_enable_alignfault()
337 {
338 	register rt_uint32_t i;
339 
340 	/* read control register */
341 	asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
342 
343 	i |= (1 << 1);
344 
345 	/* write back to control register */
346 	asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
347 }
348 
349 void mmu_disable_alignfault()
350 {
351 	register rt_uint32_t i;
352 
353 	/* read control register */
354 	asm volatile ("mrc p15, 0, %0, c1, c0, 0":"=r" (i));
355 
356 	i &= ~(1 << 1);
357 
358 	/* write back to control register */
359 	asm volatile ("mcr p15, 0, %0, c1, c0, 0": :"r" (i));
360 }
361 
362 void mmu_clean_invalidated_cache_index(int index)
363 {
364 	asm volatile ("mcr p15, 0, %0, c7, c14, 2": :"r" (index));
365 }
366 
367 void mmu_clean_invalidated_dcache(rt_uint32_t buffer, rt_uint32_t size)
368 {
369 	unsigned int ptr;
370 
371 	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
372 
373 	while(ptr < buffer + size)
374 	{
375 		asm volatile ("mcr p15, 0, %0, c7, c14, 1": :"r" (ptr));
376 		ptr += CACHE_LINE_SIZE;
377 	}
378 }
379 
380 
381 void mmu_clean_dcache(rt_uint32_t buffer, rt_uint32_t size)
382 {
383 	unsigned int ptr;
384 
385 	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
386 
387 	while (ptr < buffer + size)
388 	{
389 		asm volatile ("mcr p15, 0, %0, c7, c10, 1": :"r" (ptr));
390 		ptr += CACHE_LINE_SIZE;
391 	}
392 }
393 
394 void mmu_invalidate_dcache(rt_uint32_t buffer, rt_uint32_t size)
395 {
396 	unsigned int ptr;
397 
398 	ptr = buffer & ~(CACHE_LINE_SIZE - 1);
399 
400 	while (ptr < buffer + size)
401 	{
402 		asm volatile ("mcr p15, 0, %0, c7, c6, 1": :"r" (ptr));
403 		ptr += CACHE_LINE_SIZE;
404 	}
405 }
406 
407 void mmu_invalidate_tlb()
408 {
409 	asm volatile ("mcr p15, 0, %0, c8, c7, 0": :"r" (0));
410 }
411 
412 void mmu_invalidate_icache()
413 {
414 	asm volatile ("mcr p15, 0, %0, c7, c5, 0": :"r" (0));
415 }
416 
417 void mmu_invalidate_dcache_all()
418 {
419 	asm volatile ("mcr p15, 0, %0, c7, c6, 0": :"r" (0));
420 }
421 #endif
422 
423 /* level1 page table */
424 static volatile unsigned int _pgd_table[4*1024] ALIGN(16*1024);
425 /*
426  * level2 page table
427  * RT_MMU_PTE_SIZE must be 1024*n
428  */
429 #define RT_MMU_PTE_SIZE		4096
430 static volatile unsigned int _pte_table[RT_MMU_PTE_SIZE] ALIGN(1*1024);
431 
432 void mmu_create_pgd(struct mem_desc *mdesc)
433 {
434 	volatile rt_uint32_t *pTT;
435 	volatile int i, nSec;
436 	pTT = (rt_uint32_t *)_pgd_table + (mdesc->vaddr_start >> 20);
437 	nSec = (mdesc->vaddr_end >> 20) - (mdesc->vaddr_start >> 20);
438 	for(i = 0; i <= nSec; i++)
439 	{
440 		*pTT = mdesc->sect_attr | (((mdesc->paddr_start >> 20) + i) << 20);
441 		pTT++;
442 	}
443 }
444 
445 void mmu_create_pte(struct mem_desc *mdesc)
446 {
447 	volatile rt_uint32_t *pTT;
448 	volatile rt_uint32_t *p_pteentry;
449 	int i;
450 	rt_uint32_t vaddr;
451 	rt_uint32_t total_page = 0;
452 	rt_uint32_t pte_offset = 0;
453 	rt_uint32_t sect_attr = 0;
454 
455 	total_page = (mdesc->vaddr_end >> 12) - (mdesc->vaddr_start >> 12) + 1;
456 	pte_offset = mdesc->sect_attr & 0xfffffc00;
457 	sect_attr = mdesc->sect_attr & 0x3ff;
458 	vaddr = mdesc->vaddr_start;
459 
460 	for(i = 0; i < total_page; i++)
461 	{
462 		pTT = (rt_uint32_t *)_pgd_table + (vaddr >> 20);
463 		if (*pTT == 0) /* Level 1 page table item not used, now update pgd item */
464 		{
465 			*pTT = pte_offset | sect_attr;
466 			p_pteentry = (rt_uint32_t *)pte_offset +
467 				((vaddr & 0x000ff000) >> 12);
468 			pte_offset += 1024;
469 		}
470 		else /* using old Level 1 page table item */
471 		{
472 			p_pteentry = (rt_uint32_t *)(*pTT & 0xfffffc00) +
473 				((vaddr & 0x000ff000) >> 12);
474 		}
475 
476 
477 		*p_pteentry = mdesc->page_attr | (((mdesc->paddr_start >> 12) + i) << 12);
478 		vaddr += 0x1000;
479 	}
480 }
481 
482 static void build_pte_mem_desc(struct mem_desc *mdesc, rt_uint32_t size)
483 {
484 	rt_uint32_t pte_offset = 0;
485 	rt_uint32_t nsec = 0;
486 	/* set page table */
487 	for (; size > 0; size--)
488 	{
489 		if (mdesc->mapped_mode == PAGE_MAPPED)
490 		{
491 			nsec = (RT_ALIGN(mdesc->vaddr_end, 0x100000) - RT_ALIGN_DOWN(mdesc->vaddr_start, 0x100000)) >> 20;
492 			mdesc->sect_attr |= (((rt_uint32_t)_pte_table)& 0xfffffc00) + pte_offset;
493 			pte_offset += nsec << 10;
494 		}
495 		if (pte_offset >= RT_MMU_PTE_SIZE)
496 		{
497 			rt_kprintf("PTE table size too little\n");
498 			RT_ASSERT(0);
499 		}
500 
501 		mdesc++;
502 	}
503 }
504 
505 
506 void rt_hw_mmu_init(struct mem_desc *mdesc, rt_uint32_t size)
507 {
508 	/* disable I/D cache */
509 	mmu_disable_dcache();
510 	mmu_disable_icache();
511 	mmu_disable();
512 	mmu_invalidate_tlb();
513 
514 	/* clear pgd and pte table */
515 	rt_memset((void *)_pgd_table, 0, 16*1024);
516 	rt_memset((void *)_pte_table, 0, RT_MMU_PTE_SIZE);
517 	build_pte_mem_desc(mdesc, size);
518 	/* set page table */
519 	for (; size > 0; size--)
520 	{
521 		if (mdesc->mapped_mode == SECT_MAPPED)
522 		{
523 			mmu_create_pgd(mdesc);
524 		}
525 		else
526 		{
527 			mmu_create_pte(mdesc);
528 		}
529 
530 		mdesc++;
531 	}
532 
533 	/* set MMU table address */
534 	mmu_setttbase((rt_uint32_t)_pgd_table);
535 
536 	/* enables MMU */
537 	mmu_enable();
538 
539 	/* enable Instruction Cache */
540 	mmu_enable_icache();
541 
542 	/* enable Data Cache */
543 	mmu_enable_dcache();
544 
545 	mmu_invalidate_icache();
546 	mmu_invalidate_dcache_all();
547 }
548 
549