1
2
3
4
5
6
7
8
9
10#include <linux/init.h>
11#include <linux/mman.h>
12#include <linux/mm.h>
13#include <linux/kernel.h>
14#include <linux/ptrace.h>
15#include <linux/delay.h>
16#include <linux/bootmem.h>
17#include <linux/bitops.h>
18#include <linux/module.h>
19#include <linux/sched/mm.h>
20
21#include <asm/setup.h>
22#include <asm/traps.h>
23#include <linux/uaccess.h>
24#include <asm/page.h>
25#include <asm/pgtable.h>
26#include <asm/sun3mmu.h>
27#include <asm/segment.h>
28#include <asm/oplib.h>
29#include <asm/mmu_context.h>
30#include <asm/dvma.h>
31
32
33#undef DEBUG_MMU_EMU
34#define DEBUG_PROM_MAPS
35
36
37
38
39
40#define CONTEXTS_NUM 8
41#define SEGMAPS_PER_CONTEXT_NUM 2048
42#define PAGES_PER_SEGMENT 16
43#define PMEGS_NUM 256
44#define PMEG_MASK 0xFF
45
46
47
48
49
50unsigned long m68k_vmalloc_end;
51EXPORT_SYMBOL(m68k_vmalloc_end);
52
53unsigned long pmeg_vaddr[PMEGS_NUM];
54unsigned char pmeg_alloc[PMEGS_NUM];
55unsigned char pmeg_ctx[PMEGS_NUM];
56
57
58
59static struct mm_struct *ctx_alloc[CONTEXTS_NUM] = {
60 [0] = (struct mm_struct *)0xffffffff
61};
62
63
64static unsigned char ctx_avail = CONTEXTS_NUM-1;
65
66
67
68
69unsigned long rom_pages[256];
70
71
72void print_pte (pte_t pte)
73{
74#if 0
75
76 unsigned long val = pte_val (pte);
77 pr_cont(" pte=%lx [addr=%lx",
78 val, (val & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT);
79 if (val & SUN3_PAGE_VALID) pr_cont(" valid");
80 if (val & SUN3_PAGE_WRITEABLE) pr_cont(" write");
81 if (val & SUN3_PAGE_SYSTEM) pr_cont(" sys");
82 if (val & SUN3_PAGE_NOCACHE) pr_cont(" nocache");
83 if (val & SUN3_PAGE_ACCESSED) pr_cont(" accessed");
84 if (val & SUN3_PAGE_MODIFIED) pr_cont(" modified");
85 switch (val & SUN3_PAGE_TYPE_MASK) {
86 case SUN3_PAGE_TYPE_MEMORY: pr_cont(" memory"); break;
87 case SUN3_PAGE_TYPE_IO: pr_cont(" io"); break;
88 case SUN3_PAGE_TYPE_VME16: pr_cont(" vme16"); break;
89 case SUN3_PAGE_TYPE_VME32: pr_cont(" vme32"); break;
90 }
91 pr_cont("]\n");
92#else
93
94 unsigned long val = pte_val (pte);
95 char flags[7], *type;
96
97 flags[0] = (val & SUN3_PAGE_VALID) ? 'v' : '-';
98 flags[1] = (val & SUN3_PAGE_WRITEABLE) ? 'w' : '-';
99 flags[2] = (val & SUN3_PAGE_SYSTEM) ? 's' : '-';
100 flags[3] = (val & SUN3_PAGE_NOCACHE) ? 'x' : '-';
101 flags[4] = (val & SUN3_PAGE_ACCESSED) ? 'a' : '-';
102 flags[5] = (val & SUN3_PAGE_MODIFIED) ? 'm' : '-';
103 flags[6] = '\0';
104
105 switch (val & SUN3_PAGE_TYPE_MASK) {
106 case SUN3_PAGE_TYPE_MEMORY: type = "memory"; break;
107 case SUN3_PAGE_TYPE_IO: type = "io" ; break;
108 case SUN3_PAGE_TYPE_VME16: type = "vme16" ; break;
109 case SUN3_PAGE_TYPE_VME32: type = "vme32" ; break;
110 default: type = "unknown?"; break;
111 }
112
113 pr_cont(" pte=%08lx [%07lx %s %s]\n",
114 val, (val & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT, flags, type);
115#endif
116}
117
118
119void print_pte_vaddr (unsigned long vaddr)
120{
121 pr_cont(" vaddr=%lx [%02lx]", vaddr, sun3_get_segmap (vaddr));
122 print_pte (__pte (sun3_get_pte (vaddr)));
123}
124
125
126
127
128void __init mmu_emu_init(unsigned long bootmem_end)
129{
130 unsigned long seg, num;
131 int i,j;
132
133 memset(rom_pages, 0, sizeof(rom_pages));
134 memset(pmeg_vaddr, 0, sizeof(pmeg_vaddr));
135 memset(pmeg_alloc, 0, sizeof(pmeg_alloc));
136 memset(pmeg_ctx, 0, sizeof(pmeg_ctx));
137
138
139
140 bootmem_end = (bootmem_end + (2 * SUN3_PMEG_SIZE)) & ~SUN3_PMEG_MASK;
141
142
143 for (i=0; i < __pa(bootmem_end) / SUN3_PMEG_SIZE ; ++i)
144 pmeg_alloc[i] = 2;
145
146
147
148
149 for(num = 0xf0; num <= 0xff; num++)
150 pmeg_alloc[num] = 2;
151
152
153 for(seg = bootmem_end; seg < 0x0f800000; seg += SUN3_PMEG_SIZE) {
154 i = sun3_get_segmap(seg);
155
156 if(!pmeg_alloc[i]) {
157#ifdef DEBUG_MMU_EMU
158 pr_info("freed:");
159 print_pte_vaddr (seg);
160#endif
161 sun3_put_segmap(seg, SUN3_INVALID_PMEG);
162 }
163 }
164
165 j = 0;
166 for (num=0, seg=0x0F800000; seg<0x10000000; seg+=16*PAGE_SIZE) {
167 if (sun3_get_segmap (seg) != SUN3_INVALID_PMEG) {
168#ifdef DEBUG_PROM_MAPS
169 for(i = 0; i < 16; i++) {
170 pr_info("mapped:");
171 print_pte_vaddr (seg + (i*PAGE_SIZE));
172 break;
173 }
174#endif
175
176
177 if (!m68k_vmalloc_end)
178 m68k_vmalloc_end = seg;
179
180
181
182
183 pmeg_alloc[sun3_get_segmap(seg)] = 2;
184 }
185 }
186
187 dvma_init();
188
189
190
191
192 for(seg = 0; seg < PAGE_OFFSET; seg += SUN3_PMEG_SIZE)
193 sun3_put_segmap(seg, SUN3_INVALID_PMEG);
194
195 set_fs(MAKE_MM_SEG(3));
196 for(seg = 0; seg < 0x10000000; seg += SUN3_PMEG_SIZE) {
197 i = sun3_get_segmap(seg);
198 for(j = 1; j < CONTEXTS_NUM; j++)
199 (*(romvec->pv_setctxt))(j, (void *)seg, i);
200 }
201 set_fs(KERNEL_DS);
202
203}
204
205
206
207
208
209
210void clear_context(unsigned long context)
211{
212 unsigned char oldctx;
213 unsigned long i;
214
215 if(context) {
216 if(!ctx_alloc[context])
217 panic("clear_context: context not allocated\n");
218
219 ctx_alloc[context]->context = SUN3_INVALID_CONTEXT;
220 ctx_alloc[context] = (struct mm_struct *)0;
221 ctx_avail++;
222 }
223
224 oldctx = sun3_get_context();
225
226 sun3_put_context(context);
227
228 for(i = 0; i < SUN3_INVALID_PMEG; i++) {
229 if((pmeg_ctx[i] == context) && (pmeg_alloc[i] == 1)) {
230 sun3_put_segmap(pmeg_vaddr[i], SUN3_INVALID_PMEG);
231 pmeg_ctx[i] = 0;
232 pmeg_alloc[i] = 0;
233 pmeg_vaddr[i] = 0;
234 }
235 }
236
237 sun3_put_context(oldctx);
238}
239
240
241
242
243
244
245
246unsigned long get_free_context(struct mm_struct *mm)
247{
248 unsigned long new = 1;
249 static unsigned char next_to_die = 1;
250
251 if(!ctx_avail) {
252
253 new = next_to_die;
254 clear_context(new);
255 next_to_die = (next_to_die + 1) & 0x7;
256 if(!next_to_die)
257 next_to_die++;
258 } else {
259 while(new < CONTEXTS_NUM) {
260 if(ctx_alloc[new])
261 new++;
262 else
263 break;
264 }
265
266 if(new == CONTEXTS_NUM)
267 panic("get_free_context: failed to find free context");
268 }
269
270 ctx_alloc[new] = mm;
271 ctx_avail--;
272
273 return new;
274}
275
276
277
278
279
280
281
282
283
284inline void mmu_emu_map_pmeg (int context, int vaddr)
285{
286 static unsigned char curr_pmeg = 128;
287 int i;
288
289
290 vaddr &= ~SUN3_PMEG_MASK;
291
292
293 while (pmeg_alloc[curr_pmeg] == 2)
294 ++curr_pmeg;
295
296
297#ifdef DEBUG_MMU_EMU
298 pr_info("mmu_emu_map_pmeg: pmeg %x to context %d vaddr %x\n",
299 curr_pmeg, context, vaddr);
300#endif
301
302
303 if (pmeg_alloc[curr_pmeg] == 1) {
304 sun3_put_context(pmeg_ctx[curr_pmeg]);
305 sun3_put_segmap (pmeg_vaddr[curr_pmeg], SUN3_INVALID_PMEG);
306 sun3_put_context(context);
307 }
308
309
310
311 if(vaddr >= PAGE_OFFSET) {
312
313 unsigned char i;
314
315 for(i = 0; i < CONTEXTS_NUM; i++) {
316 sun3_put_context(i);
317 sun3_put_segmap (vaddr, curr_pmeg);
318 }
319 sun3_put_context(context);
320 pmeg_alloc[curr_pmeg] = 2;
321 pmeg_ctx[curr_pmeg] = 0;
322
323 }
324 else {
325 pmeg_alloc[curr_pmeg] = 1;
326 pmeg_ctx[curr_pmeg] = context;
327 sun3_put_segmap (vaddr, curr_pmeg);
328
329 }
330 pmeg_vaddr[curr_pmeg] = vaddr;
331
332
333 for (i=0; i<SUN3_PMEG_SIZE; i+=SUN3_PTE_SIZE)
334 sun3_put_pte (vaddr + i, SUN3_PAGE_SYSTEM);
335
336
337 ++curr_pmeg;
338}
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356int mmu_emu_handle_fault (unsigned long vaddr, int read_flag, int kernel_fault)
357{
358 unsigned long segment, offset;
359 unsigned char context;
360 pte_t *pte;
361 pgd_t * crp;
362
363 if(current->mm == NULL) {
364 crp = swapper_pg_dir;
365 context = 0;
366 } else {
367 context = current->mm->context;
368 if(kernel_fault)
369 crp = swapper_pg_dir;
370 else
371 crp = current->mm->pgd;
372 }
373
374#ifdef DEBUG_MMU_EMU
375 pr_info("mmu_emu_handle_fault: vaddr=%lx type=%s crp=%p\n",
376 vaddr, read_flag ? "read" : "write", crp);
377#endif
378
379 segment = (vaddr >> SUN3_PMEG_SIZE_BITS) & 0x7FF;
380 offset = (vaddr >> SUN3_PTE_SIZE_BITS) & 0xF;
381
382#ifdef DEBUG_MMU_EMU
383 pr_info("mmu_emu_handle_fault: segment=%lx offset=%lx\n", segment,
384 offset);
385#endif
386
387 pte = (pte_t *) pgd_val (*(crp + segment));
388
389
390 if (!pte) {
391
392 return 0;
393 }
394
395 pte = (pte_t *) __va ((unsigned long)(pte + offset));
396
397
398 if (!(pte_val (*pte) & SUN3_PAGE_VALID))
399 return 0;
400
401
402 if (sun3_get_segmap (vaddr&~SUN3_PMEG_MASK) == SUN3_INVALID_PMEG)
403 mmu_emu_map_pmeg (context, vaddr);
404
405
406 sun3_put_pte (vaddr&PAGE_MASK, pte_val (*pte));
407
408
409
410
411
412
413 if (!read_flag) {
414 if (pte_val (*pte) & SUN3_PAGE_WRITEABLE)
415 pte_val (*pte) |= (SUN3_PAGE_ACCESSED
416 | SUN3_PAGE_MODIFIED);
417 else
418 return 0;
419 } else
420 pte_val (*pte) |= SUN3_PAGE_ACCESSED;
421
422#ifdef DEBUG_MMU_EMU
423 pr_info("seg:%ld crp:%p ->", get_fs().seg, crp);
424 print_pte_vaddr (vaddr);
425 pr_cont("\n");
426#endif
427
428 return 1;
429}
430