]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/omap4/mmu.c
kernel: fix fairshare formula in comment (thanks erik)
[plan9front.git] / sys / src / 9 / omap4 / mmu.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "arm.h"
8
9 char iopages[NIOPAGES / 8];
10 Lock iopagelock;
11 uchar *periph;
12
13 static int
14 isfree(int i)
15 {
16         return (iopages[i / 8] & (1 << (i % 8))) == 0;
17 }
18
19 static void
20 freeio(int i)
21 {
22         iopages[i / 8] &= ~(1 << (i % 8));
23 }
24
25 static int
26 getiopages(int n)
27 {
28         int i, j;
29
30         lock(&iopagelock);
31         for(i = 0; i <= NIOPAGES - n; i++){
32                 for(j = 0; j < n; j++)
33                         if(!isfree(i + j))
34                                 goto next;
35                 for(j = 0; j < n; j++)
36                         iopages[(i + j) / 8] |= (1 << ((i + j) % 8));
37                 unlock(&iopagelock);
38                 return i;
39         next: ;
40         }
41         panic("out of i/o pages");
42         return 0;
43 }
44
45 static void
46 putiopages(int i, int n)
47 {
48         lock(&iopagelock);
49         while(n--)
50                 freeio(i++);
51         unlock(&iopagelock);
52 }
53
54 void *
55 vmap(ulong phys, ulong length)
56 {
57         ulong virt, off, *l2;
58
59         off = phys % BY2PG;
60         length = (ROUNDUP(phys + length, BY2PG) - ROUNDDN(phys, BY2PG)) / BY2PG;
61         if(length == 0)
62                 return nil;
63         phys = ROUNDDN(phys, BY2PG);
64         virt = getiopages(length);
65         l2 = KADDR(IOPT);
66         l2 += virt;
67         while(length--){
68                 *l2++ = phys | L2AP(Krw) | Small | PTEIO;
69                 phys += BY2PG;
70         }
71         flushtlb();
72         return (void *) (IZERO + BY2PG * virt + off);
73 }
74
75 void
76 vunmap(void *virt, ulong length)
77 {
78         ulong v, *l2;
79         
80         if((ulong)virt < IZERO || (ulong)virt >= IZERO + NIOPAGES * BY2PG)
81                 panic("vunmap: virt=%p", virt);
82         v = (ROUNDDN((ulong) virt, BY2PG) - IZERO) / BY2PG;
83         length = (ROUNDUP(((ulong) virt) + length, BY2PG) - ROUNDDN((ulong) virt, BY2PG)) / BY2PG;
84         if(length == 0)
85                 return;
86         l2 = KADDR(IOPT);
87         l2 += v;
88         lock(&iopagelock);
89         while(length--){
90                 *l2++ = 0;
91                 freeio(v++);
92         }
93         unlock(&iopagelock);
94         flushtlb();
95 }
96
97 void
98 markidle(int n)
99 {
100         setgpio(7 + m->machno, !n);
101 }
102
103 void
104 mmuinit(void)
105 {
106         ulong *l1, l2, *pl2;
107         int i, n;
108         extern ulong *uart;
109
110         l1 = KADDR(L1PT);
111         l2 = IOPT;
112         n = NIOPAGES / 256;
113         memset(KADDR(l2), 0, n * L2SIZ);
114         for(i = 0; i < n; i++){
115                 l1[(IZERO / MiB) + i] = l2 | Coarse;
116                 l2 += L2SIZ;
117         }
118         uart = vmap((ulong) uart, BY2PG);
119         periph = vmap(0x48240000, 2 * BY2PG);
120         memset(l1, 0, sizeof(ulong) * (IZERO / MiB));
121         l1[4095] = PRIVL2 | Coarse;
122         pl2 = KADDR(PRIVL2);
123         for(i = 0; i < 240; i++)
124                 pl2[i] = (0x8FF00000 + i * BY2PG) | L2AP(Krw) | Small | Cached | Buffered;
125         pl2[240] = PHYSVECTORS | L2AP(Krw) | Small | Cached | Buffered;
126         pl2[241] = FIRSTMACH | L2AP(Krw) | Small | Cached | Buffered;
127         flushtlb();
128         m = (Mach *) MACHADDR;
129 }
130
131 void
132 mmuswitch(Proc *p)
133 {
134         ulong *l1;
135         
136         l1 = KADDR(L1PT);
137         memmove(l1, p->l1, sizeof p->l1);
138         flushtlb();
139 }
140
141 void
142 putmmu(ulong va, ulong pa, Page *)
143 {
144         ulong *l1a, *l1b, *l2;
145         int l1o, l2o;
146         
147         l1o = va / MiB;
148         l2o = (va % MiB) / BY2PG;
149         l1a = KADDR(L1PT);
150         l1b = up->l1;
151         if(l1a[l1o] == 0){
152                 if((pa & PTEVALID) == 0)
153                         return;
154                 l2 = xspanalloc(L2SIZ, L2SIZ, 0);
155                 l1a[l1o] = l1b[l1o] = PADDR(l2) | Coarse;
156         } else
157                 l2 = KADDR(ROUNDDN(l1a[l1o], L2SIZ));
158         l2 += l2o;
159         if((pa & PTEVALID) == 0){
160                 *l2 = 0;
161                 flushtlb();
162                 return;
163         }
164         *l2 = ROUNDDN(pa, BY2PG) | Small;
165         if((pa & PTEWRITE) == 0)
166                 *l2 |= L2AP(Uro);
167         else
168                 *l2 |= L2AP(Urw);
169         if((pa & PTEUNCACHED) == 0)
170                 *l2 |= Buffered | Cached;
171         flushtlb();
172 }
173
174 void
175 flushmmu(void)
176 {
177         int s, i;
178         ulong p;
179         ulong *l1;
180
181         l1 = KADDR(L1PT);
182         s = splhi();
183         for(i = 0; i < nelem(up->l1); i++){
184                 p = l1[i];
185                 if(p & Small)
186                         free(KADDR(ROUNDDN(p, BY2PG)));
187         }
188         memset(up->l1, 0, sizeof up->l1);
189         memset(l1, 0, sizeof up->l1);
190         flushtlb();
191         splx(s);
192 }
193
194 void
195 mmurelease(Proc *p)
196 {
197         int i;
198         ulong pg;
199
200         if(p == up){
201                 flushmmu();
202                 return;
203         }
204         for(i = 0; i < nelem(p->l1); i++){
205                 pg = p->l1[i];
206                 if(pg & Small)
207                         free(KADDR(ROUNDDN(pg, BY2PG)));
208         }
209         memset(p->l1, 0, sizeof p->l1);
210 }
211
212 void
213 countpagerefs()
214 {
215         panic("countpagerefs");
216 }
217
218 void*
219 KADDR(ulong pa)
220 {
221         if(pa < (ulong)PHYSDRAM || pa > (ulong)(PHYSDRAM + VECTORS - KZERO))
222                 panic("kaddr: pa=%#.8lux, pc=%p", pa, getcallerpc(&pa));
223         return (void*)(pa + KZERO - PHYSDRAM);
224 }
225
226 ulong
227 paddr(void* v)
228 {
229         ulong va;
230         
231         va = (ulong) v;
232         if(va < KZERO)
233                 panic("paddr: v=%p", v);
234         return va - KZERO + PHYSDRAM;
235 }
236
237 ulong
238 cankaddr(ulong arg)
239 {
240         if(arg < PHYSDRAM || arg > (ulong)(PHYSDRAM + VECTORS - KZERO))
241                 return 0;
242         return PHYSDRAM - KZERO - arg;
243 }