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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
|
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
/*
* Small pages:
* L1: 12-bit index -> 4096 descriptors -> 16Kb
* L2: 8-bit index -> 256 descriptors -> 1Kb
* Each L2 descriptor has access permissions for 4 1Kb sub-pages.
*
* TTB + L1Tx gives address of L1 descriptor
* L1 descriptor gives PTBA
* PTBA + L2Tx gives address of L2 descriptor
* L2 descriptor gives PBA
*
* C & B are interpreted as follows:
* C=0 B=0 uncached, unbuffered, stall until data access complete
* C=0 B=1 uncached, buffered
* C=1 B=0 write-through cachable
* C=1 B=1 write-back cachable
* and the i-cache uses only the C bit (cached if non-zero).
*/
#define TTB(pa) ((pa) & ~0x3FFF) /* translation table base */
#define L1x(pa) (((pa)>>20) & 0xFFF) /* L1 table index */
#define PTBA(pa) ((pa) & ~0x3FF) /* page table base address */
#define L2x(pa) (((pa)>>12) & 0xFF) /* L2 table index */
#define PBA(pa) ((pa) & ~0xFFF) /* page base address */
#define SBA(pa) ((pa) & ~0xFFFFF) /* section base address */
enum {
/* sizes */
Section= 1<<20,
LargePage= 1<<16,
SmallPage= 1<<12,
EsmallPage= 1<<10,
SectionPages = Section/SmallPage,
PtAlign = 1<<10,
/* L1 descriptor format */
L1type= 3<<0, /* mask for type */
L1page= 1<<0, /* descriptor is for L2 pages */
L1section= 2<<0, /* descriptor is for section */
L1fpage= 3<<0, /* descriptor is for fine (1k) L2 pages */
L1buffered= 1<<2,
L1cached= 1<<3,
L1mbo= 1<<4, /* must be one */
/* L2 descriptor format for coarse page table */
L2type= 3<<0, /* mask for type */
L2invalid= 0<<0,
L2large= 1<<0, /* large page */
L2small= 2<<0, /* small page */
L2esmall= 3<<0, /* extended small page */
L2buffered= 1<<2,
L2cached= 1<<3,
/* then access permissions */
L2smallX= 1<<6,
L2largeX= 1<<12,
/* domains */
Dnone= 0,
Dclient= 1,
Dmanager= 3,
/* access permissions */
APsro= 0, /* supervisor ro if S|R */
APsrw= 1, /* supervisor rw */
APuro= 2, /* supervisor rw + user ro */
APurw= 3, /* supervisor rw + user rw */
};
#define L1dom(d) (((d) & 0xF)<<5) /* L1 domain */
#define AP(i, v) ((v)<<(((i)*2)+4)) /* access permissions */
#define L1AP(v) AP(3, (v))
#define L2AP(v) AP(3, (v))|AP(2, (v))|AP(1, (v))|AP(0, (v))
#define L1krw (L1AP(APsrw) | L1dom(0))
/*
* return physical address corresponding to a given virtual address,
* or 0 if there is no such address
*/
ulong
va2pa(void *v)
{
int idx;
ulong pte, ste, *ttb;
idx = L1x((ulong)v);
ttb = (ulong*)KTTB;
ste = ttb[idx];
switch(ste & L1type) {
case L1section:
return SBA(ste)|((ulong)v & 0x000fffff);
case L1page:
pte = ((ulong *)PTBA(ste))[L2x((ulong)v)];
switch(pte & 3) {
case L2large:
return (pte & 0xffff0000)|((ulong)v & 0x0000ffff);
case L2small:
return (pte & 0xfffff000)|((ulong)v & 0x00000fff);
}
}
return 0;
}
/* for debugging */
void
prs(char *s)
{
serialputs(s, strlen(s));
}
void
pr16(ulong n)
{
int i, c;
for(i=28; i>=0; i-=4){
c = (n>>i) & 0xF;
if(c >= 0 && c <= 9)
c += '0';
else
c += 'A'-10;
serialputc(c);
}
}
void
xdelay(int n)
{
int j;
for(j=0; j<1000000/4; j++)
n++;
USED(n);
}
void*
mmuphysmap(void *va, ulong pa, ulong nbytes)
{
ulong *ttb;
ulong p, o;
if(va == nil)
va = KADDR(pa);
p = (ulong)va;
if((pa|p) & (Section-1))
panic("kmapphys");
ttb = (ulong*)KTTB;
nbytes = (nbytes+Section-1)&~(Section-1);
for(o = 0; o < nbytes; o += Section)
ttb[L1x(p+o)] = (pa+o) | (1<<4) | L1krw | L1section;
return va;
}
void*
mmukaddr(ulong pa)
{
if(pa >= PHYSDRAM0 && pa < conf.topofmem)
return (void*)(KZERO+(pa-PHYSDRAM0));
return (void*)pa;
}
/*
* Set a 1-1 map of virtual to physical memory, except:
* kernel is mapped to KZERO
* doubly-map page0 at the alternative interrupt vector address,
* doubly-map physical memory at KZERO+256*MB as uncached but buffered,
* map flash to virtual space away from 0,
* disable access to 0 (nil pointers).
*
* Other section maps are added later as required by mmuphysmap.
*/
void
mmuinit(void)
{
int i;
ulong *ttb, *ptable;
ttb = (ulong*)KTTB;
memset(ttb, 0, 16384);
/* assume flash is first in special physical space */
for(i = L1x(PHYSFLASH0); i < 0x1000; i++)
ttb[i] = (i<<20) | L1krw | (1<<4) | L1section;
/* cached dram at normal kernel addresses */
for(i = 0; i < 32*MB; i += MB)
ttb[L1x(KZERO+i)] = (PHYSDRAM0+i) | (1<<4) | L1krw | L1section | L1cached | L1buffered;
/* aliases for uncached dram */
for(i = 0; i < 64*MB; i += MB)
ttb[L1x(UCDRAMZERO+i)] = (PHYSDRAM0+i) | L1krw | (1<<4) | L1section;
/* TO DO: make the text read only */
/* remap flash */
for(i=0; i<8*MB; i+=MB)
ttb[L1x(FLASHMEM+i)] = (PHYSFLASH0+i) | L1krw | (1<<4) | L1section; /* we'll make flash uncached for now */
/*
* build page table for alternative vector page, mapping trap vectors in *page0
*/
ptable = xspanalloc(SectionPages*sizeof(*ptable), PtAlign, 0);
ptable[L2x(AIVECADDR)] = PADDR(page0) | L2AP(APsrw) | L2cached | L2buffered | L2small;
ttb[L1x(AIVECADDR)] = PADDR(ptable) | (1<<4) | L1page;
mmuputttb(KTTB & ~KZERO);
mmuputdac(Dclient);
mmuputctl(mmugetctl() | CpCaltivec | CpCIcache | CpCsystem | CpCwpd | CpCDcache | CpCmmu);
tlbinvalidateall();
}
/*
* flush data in a given address range to memory
* and invalidate the region in the instruction cache.
*/
int
segflush(void *a, ulong n)
{
dcflush(a, n);
icflush(a, n);
return 0;
}
/*
* return an uncached alias for the memory at a
*/
void*
mmucacheinhib(void *a, ulong nb)
{
ulong p;
if(a == nil)
return nil;
p = PADDR(a);
if(p & (CACHELINESZ-1))
panic("mmucacheinhib");
dcflush(a, nb);
return (void*)(UCDRAMZERO|PADDR(a));
}
|