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