-
Notifications
You must be signed in to change notification settings - Fork 16
/
mmu.c
132 lines (108 loc) · 3.5 KB
/
mmu.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
/*
mmu.c:
Copyright (C) 2009 david leels <davidontech@gmail.com>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
*/
#ifdef TEST_MMU
#include <stdio.h>
#endif
#define PTE_BITS_L1_SECTION (0x2)
#define PTE_L1_SECTION_PADDR_BASE_MASK (0xfff00000)
#define PAGE_TABLE_L1_BASE_ADDR_MASK (0xffffc000)
#define VIRT_TO_PTE_L1_INDEX(addr) (((addr) & 0xfff00000) >> 18)
#define RPI2
#ifdef RPI2
#define PTE_L1_SECTION_NO_CACHE_AND_WB (0x0<<2)
#define PTE_L1_SECTION_DOMAIN_DEFAULT (0x0<<5)
#define PTE_ALL_AP_L1_SECTION_DEFAULT (0x1<<10)
#define L1_PTR_BASE_ADDR 0x30700000
#define PHYSICAL_MEM_ADDR 0x00000000
#define VIRTUAL_MEM_ADDR 0x00000000
#define MEM_MAP_SIZE 0x40000000
#define PHYSICAL_IO_ADDR 0x3F000000
#define VIRTUAL_IO_ADDR 0xc8000000
#define IO_MAP_SIZE 0x18000000
#else
/*mask for page table base addr*/
#define PTE_L1_SECTION_NO_CACHE_AND_WB (0x0<<2)
#define PTE_L1_SECTION_DOMAIN_DEFAULT (0x0<<5)
#define PTE_ALL_AP_L1_SECTION_DEFAULT (0x1<<10)
#define L1_PTR_BASE_ADDR 0x30700000
#define PHYSICAL_MEM_ADDR 0x30000000
#define VIRTUAL_MEM_ADDR 0x30000000
#define MEM_MAP_SIZE 0x800000
#define PHYSICAL_IO_ADDR 0x48000000
#define VIRTUAL_IO_ADDR 0xc8000000
#define IO_MAP_SIZE 0x18000000
#endif
#ifndef TEST_MMU
void start_mmu(void){
unsigned int ttb=L1_PTR_BASE_ADDR;
asm (
"mcr p15,0,%0,c2,c0,0\n" /* set base address of page table*/
"mvn r0,#0\n"
"mcr p15,0,r0,c3,c0,0\n" /* enable all region access*/
"mov r0,#0x1\n"
"mcr p15,0,r0,c1,c0,0\n" /* set back to control register */
"mov r0,r0\n"
"mov r0,r0\n"
"mov r0,r0\n"
:
: "r" (ttb)
:"r0"
);
}
#endif
unsigned int gen_l1_pte(unsigned int paddr){
return (paddr & PTE_L1_SECTION_PADDR_BASE_MASK);
}
unsigned int gen_l1_pte_addr(unsigned int baddr, unsigned int vaddr){
return (baddr & PAGE_TABLE_L1_BASE_ADDR_MASK) | VIRT_TO_PTE_L1_INDEX(vaddr);
}
void init_sys_mmu(void){
unsigned int pte;
unsigned int pte_addr;
int j;
for(j=0;j<MEM_MAP_SIZE>>20;j++){
pte = gen_l1_pte(PHYSICAL_MEM_ADDR+(j<<20));
pte |= PTE_BITS_L1_SECTION;
pte |= PTE_ALL_AP_L1_SECTION_DEFAULT;
pte |= PTE_L1_SECTION_NO_CACHE_AND_WB;
pte |= PTE_L1_SECTION_DOMAIN_DEFAULT;
pte_addr = gen_l1_pte_addr(L1_PTR_BASE_ADDR, VIRTUAL_MEM_ADDR+(j<<20));
#ifdef TEST_MMU
printf("%d ## pte_addr: %x, pte: %x\n", j, pte_addr, pte);
#else
*(volatile unsigned int *)pte_addr=pte;
#endif
}
for(j=0;j<IO_MAP_SIZE>>20;j++){
pte=gen_l1_pte(PHYSICAL_IO_ADDR+(j<<20));
pte |= PTE_ALL_AP_L1_SECTION_DEFAULT;
pte |= PTE_L1_SECTION_NO_CACHE_AND_WB;
pte |= PTE_L1_SECTION_DOMAIN_DEFAULT;
pte_addr = gen_l1_pte_addr(L1_PTR_BASE_ADDR, VIRTUAL_IO_ADDR+(j<<20));
#ifdef TEST_MMU
printf("%d (IO) ## pte_addr: %x, pte: %x\n", j, pte_addr, pte);
#else
*(volatile unsigned int *)pte_addr=pte;
#endif
}
}
#ifdef TEST_MMU
int main(int argc, char *argv[])
{
printf("L1_PTR_BASE_ADDR: %x\n", L1_PTR_BASE_ADDR);
init_sys_mmu();
return 0;
}
#endif