This source file includes following definitions.
- sun4c_pmd_align
- sun4c_pgdir_align
- sun4c_vmalloc_start
- sun4c_update_rootmmu_dir
- sun4c_pte_none
- sun4c_pte_present
- sun4c_pte_inuse
- sun4c_pte_clear
- sun4c_pte_reuse
- sun4c_pmd_none
- sun4c_pmd_bad
- sun4c_pmd_present
- sun4c_pmd_inuse
- sun4c_pmd_clear
- sun4c_pmd_reuse
- sun4c_pgd_none
- sun4c_pgd_bad
- sun4c_pgd_present
- sun4c_pgd_inuse
- sun4c_pgd_clear
- sun4c_pte_read
- sun4c_pte_write
- sun4c_pte_exec
- sun4c_pte_dirty
- sun4c_pte_young
- sun4c_pte_cow
- sun4c_pte_wrprotect
- sun4c_pte_rdprotect
- sun4c_pte_exprotect
- sun4c_pte_mkclean
- sun4c_pte_mkold
- sun4c_pte_uncow
- sun4c_pte_mkwrite
- sun4c_pte_mkread
- sun4c_pte_mkexec
- sun4c_pte_mkdirty
- sun4c_pte_mkyoung
- sun4c_pte_mkcow
- sun4c_mk_pte
- sun4c_pte_modify
- sun4c_pte_page
- sun4c_pmd_page
- sun4c_pgd_offset
- sun4c_pmd_offset
- sun4c_pte_offset
- add_pseg_list
- remove_pseg_list
- add_pseg_ctxlist
- remove_pseg_ctxlist
- sun4c_init_pseg_lists
- sun4c_distribute_kernel_mapping
- sun4c_delete_kernel_mapping
- sun4c_lock_tlb_entry
- sun4c_unlock_tlb_entry
- sun4c_unload_context_from_tlb
- sun4c_unload_page_from_tlb
- sun4c_invalidate
- sun4c_set_pte
- sun4c_pte_free_kernel
- sun4c_pte_alloc_kernel
- sun4c_pmd_free_kernel
- sun4c_pmd_alloc_kernel
- sun4c_pte_free
- sun4c_pte_alloc
- sun4c_pmd_free
- sun4c_pmd_alloc
- sun4c_pgd_free
- sun4c_pgd_alloc
- sun4c_switch_to_context
- sun4c_mapioaddr
- sun4c_lockarea
- sun4c_unlockarea
- sun4c_get_scsi_buffer
- sun4c_release_scsi_buffer
- sun4c_get_fault_info
- sun4c_alloc_pseg
- sun4c_update_mmu_cache
- sun4c_free_all_nonlocked_psegs
- sun4c_alloc_pseg_from_free_list
- sun4c_init_lock_area
- sun4c_check_for_ss2_cache_bug
- sun4c_paging_init
- sun4c_test_wp
- sun4c_lock_entire_kernel
- sun4c_fork_hook
- sun4c_release_hook
- sun4c_flush_hook
- sun4c_task_cacheflush
- sun4c_exit_hook
- ld_mmu_sun4c
1
2
3
4
5
6
7
8
9
10
11
12 #include <linux/kernel.h>
13 #include <linux/sched.h>
14
15 #include <asm/processor.h>
16 #include <asm/page.h>
17 #include <asm/pgtable.h>
18 #include <asm/vac-ops.h>
19 #include <asm/vaddrs.h>
20 #include <asm/asi.h>
21 #include <asm/system.h>
22 #include <asm/contregs.h>
23 #include <asm/oplib.h>
24 #include <asm/idprom.h>
25 #include <asm/machines.h>
26 #include <asm/memreg.h>
27 #include <asm/kdebug.h>
28
29
30 static struct pseg_list s4cpseg_pool[256];
31
32 struct pseg_list s4cpseg_free;
33 struct pseg_list s4cpseg_used;
34 static struct pseg_list s4cpseg_locked;
35 static struct pseg_list s4cpseg_per_context[16];
36
37 static unsigned char pseg_count_per_context[16];
38
39 unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
40 unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
41
42 extern int num_segmaps, num_contexts;
43
44
45
46
47
48 #define PGD_PRESENT 0x001
49 #define PGD_RW 0x002
50 #define PGD_USER 0x004
51 #define PGD_ACCESSED 0x020
52 #define PGD_DIRTY 0x040
53 #define PGD_TABLE (PGD_PRESENT | PGD_RW | PGD_USER | PGD_ACCESSED | PGD_DIRTY)
54
55 unsigned long sun4c_vmalloc_start(void)
56 {
57 return SUN4C_VMALLOC_START;
58 }
59
60
61 void sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
62 {
63 (tsk)->tss.pgd_ptr = (unsigned long) (pgdir);
64 }
65
66 int sun4c_pte_none(pte_t pte) { return !pte_val(pte); }
67 int sun4c_pte_present(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_VALID; }
68 int sun4c_pte_inuse(pte_t *ptep) { return mem_map[MAP_NR(ptep)].reserved || mem_map[MAP_NR(ptep)].count != 1; }
69 void sun4c_pte_clear(pte_t *ptep) { pte_val(*ptep) = 0; }
70 void sun4c_pte_reuse(pte_t *ptep)
71 {
72 if(!mem_map[MAP_NR(ptep)].reserved)
73 mem_map[MAP_NR(ptep)].count++;
74 }
75
76 int sun4c_pmd_none(pmd_t pmd) { return !pmd_val(pmd); }
77 int sun4c_pmd_bad(pmd_t pmd)
78 {
79 return (pmd_val(pmd) & ~PAGE_MASK) != PGD_TABLE || pmd_val(pmd) > high_memory;
80 }
81
82 int sun4c_pmd_present(pmd_t pmd) { return pmd_val(pmd) & PGD_PRESENT; }
83 int sun4c_pmd_inuse(pmd_t *pmdp) { return 0; }
84 void sun4c_pmd_clear(pmd_t *pmdp) { pmd_val(*pmdp) = 0; }
85 void sun4c_pmd_reuse(pmd_t * pmdp) { }
86
87 int sun4c_pgd_none(pgd_t pgd) { return 0; }
88 int sun4c_pgd_bad(pgd_t pgd) { return 0; }
89 int sun4c_pgd_present(pgd_t pgd) { return 1; }
90 int sun4c_pgd_inuse(pgd_t *pgdp) { return mem_map[MAP_NR(pgdp)].reserved; }
91 void sun4c_pgd_clear(pgd_t * pgdp) { }
92
93
94
95
96
97 int sun4c_pte_read(pte_t pte) { return !(pte_val(pte) & _SUN4C_PAGE_PRIV); }
98 int sun4c_pte_write(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_WRITE; }
99 int sun4c_pte_exec(pte_t pte) { return !(pte_val(pte) & _SUN4C_PAGE_PRIV); }
100 int sun4c_pte_dirty(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
101 int sun4c_pte_young(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_REF; }
102 int sun4c_pte_cow(pte_t pte) { return pte_val(pte) & _SUN4C_PAGE_COW; }
103
104 pte_t sun4c_pte_wrprotect(pte_t pte) { pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
105 pte_t sun4c_pte_rdprotect(pte_t pte) { pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
106 pte_t sun4c_pte_exprotect(pte_t pte) { pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
107 pte_t sun4c_pte_mkclean(pte_t pte) { pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
108 pte_t sun4c_pte_mkold(pte_t pte) { pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
109 pte_t sun4c_pte_uncow(pte_t pte) { pte_val(pte) &= ~_SUN4C_PAGE_COW; return pte; }
110 pte_t sun4c_pte_mkwrite(pte_t pte) { pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
111 pte_t sun4c_pte_mkread(pte_t pte) { pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
112 pte_t sun4c_pte_mkexec(pte_t pte) { pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
113 pte_t sun4c_pte_mkdirty(pte_t pte) { pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
114 pte_t sun4c_pte_mkyoung(pte_t pte) { pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
115 pte_t sun4c_pte_mkcow(pte_t pte) { pte_val(pte) |= _SUN4C_PAGE_COW; return pte; }
116
117
118
119
120
121 pte_t sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
122 {
123 return __pte(((page - PAGE_OFFSET) >> PAGE_SHIFT) | pgprot_val(pgprot));
124 }
125
126 pte_t sun4c_pte_modify(pte_t pte, pgprot_t newprot)
127 {
128 return __pte((pte_val(pte) & _SUN4C_PAGE_CHG_MASK) | pgprot_val(newprot));
129 }
130
131 unsigned long sun4c_pte_page(pte_t pte)
132 {
133 return (PAGE_OFFSET + ((pte_val(pte) & 0xffff) << (PAGE_SHIFT)));
134 }
135
136 unsigned long sun4c_pmd_page(pmd_t pmd)
137 {
138 return (pmd_val(pmd) & PAGE_MASK);
139 }
140
141
142 pgd_t *sun4c_pgd_offset(struct mm_struct * mm, unsigned long address)
143 {
144 return mm->pgd + (address >> SUN4C_PGDIR_SHIFT);
145 }
146
147
148 pmd_t *sun4c_pmd_offset(pgd_t * dir, unsigned long address)
149 {
150 return (pmd_t *) dir;
151 }
152
153
154 pte_t *sun4c_pte_offset(pmd_t * dir, unsigned long address)
155 {
156 return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
157 }
158
159
160
161
162
163 static inline void add_pseg_list(struct pseg_list *head, struct pseg_list *entry)
164 {
165 entry->next = head;
166 (entry->prev = head->prev)->next = entry;
167 head->prev = entry;
168 }
169 #define add_to_used_pseg_list(entry) add_pseg_list(&s4cpseg_used, entry)
170 #define add_to_free_pseg_list(entry) add_pseg_list(&s4cpseg_free, entry)
171 #define add_to_locked_pseg_list(entry) add_pseg_list(&s4cpseg_locked, entry)
172
173 static inline void remove_pseg_list(struct pseg_list *entry)
174 {
175 entry->next->prev = entry->prev;
176 entry->prev->next = entry->next;
177 }
178
179 static inline void add_pseg_ctxlist(struct pseg_list *entry, int ctx)
180 {
181 struct pseg_list *head = &s4cpseg_per_context[ctx];
182
183 entry->ctx_next = head;
184 (entry->ctx_prev = head->ctx_prev)->ctx_next = entry;
185 head->ctx_prev = entry;
186 pseg_count_per_context[ctx]++;
187 }
188
189 static inline void remove_pseg_ctxlist(struct pseg_list *entry, int ctx)
190 {
191 entry->ctx_next->ctx_prev = entry->ctx_prev;
192 entry->ctx_prev->ctx_next = entry->ctx_next;
193 pseg_count_per_context[ctx]--;
194 }
195
196 static inline void sun4c_init_pseg_lists(void)
197 {
198 int i;
199
200 s4cpseg_free.prev = s4cpseg_free.next = &s4cpseg_free;
201 s4cpseg_used.prev = s4cpseg_used.next = &s4cpseg_used;
202 s4cpseg_locked.prev = s4cpseg_locked.next = &s4cpseg_locked;
203 for(i = 0; i < num_contexts; i++) {
204 s4cpseg_per_context[i].ctx_prev = s4cpseg_per_context[i].ctx_next =
205 &s4cpseg_per_context[i];
206 }
207 for(i = 0; i <= invalid_segment; i++) {
208 s4cpseg_pool[i].vaddr = 0;
209 s4cpseg_pool[i].context = 0;
210 s4cpseg_pool[i].ref_cnt = 0;
211 s4cpseg_pool[i].hardlock = 0;
212 s4cpseg_pool[i].pseg = i;
213 }
214 s4cpseg_pool[invalid_segment].hardlock = 1;
215 }
216
217 static inline void sun4c_distribute_kernel_mapping(unsigned long address,
218 unsigned char pseg)
219 {
220 unsigned int flags;
221 int ctx, save_ctx;
222
223 save_flags(flags); cli();
224 save_ctx = get_context();
225 flush_user_windows();
226 for(ctx = 0; ctx < num_contexts; ctx++) {
227 set_context(ctx);
228 put_segmap(address, pseg);
229 }
230 set_context(save_ctx);
231 restore_flags(flags);
232 }
233
234 static inline void sun4c_delete_kernel_mapping(unsigned long address)
235 {
236 unsigned int flags;
237 int ctx, save_ctx;
238
239 save_flags(flags); cli();
240 save_ctx = get_context();
241 flush_user_windows();
242
243
244 sun4c_flush_segment(address);
245 for(ctx = 0; ctx < num_contexts; ctx++) {
246 set_context(ctx);
247 put_segmap(address, invalid_segment);
248 }
249 set_context(save_ctx);
250 restore_flags(flags);
251 }
252
253
254
255
256 static inline void sun4c_lock_tlb_entry(unsigned long address)
257 {
258 unsigned long flags;
259 unsigned char pseg;
260
261 save_flags(flags); cli();
262
263 __asm__ __volatile__("ldub [%0], %%g0\n\t" : : "r" (address));
264 address &= SUN4C_REAL_PGDIR_MASK;
265 pseg = get_segmap(address);
266 if(address < KERNBASE)
267 panic("locking user address space into tlb!");
268 if(pseg == invalid_segment)
269 panic("cannot lock kernel tlb entry...");
270 if(!s4cpseg_pool[pseg].ref_cnt++ && !s4cpseg_pool[pseg].hardlock) {
271
272 remove_pseg_list(&s4cpseg_pool[pseg]);
273 add_to_locked_pseg_list(&s4cpseg_pool[pseg]);
274 }
275 restore_flags(flags);
276 }
277
278 static inline void sun4c_unlock_tlb_entry(unsigned long address)
279 {
280 unsigned long flags;
281 struct pseg_list *psegp;
282 unsigned char pseg;
283
284 save_flags(flags); cli();
285 address &= SUN4C_REAL_PGDIR_MASK;
286 pseg = get_segmap(address);
287 if(address < KERNBASE)
288 panic("unlocking user tlb entry!");
289 if(pseg == invalid_segment)
290 panic("unlocking non-locked kernel tlb entry...");
291 psegp = &s4cpseg_pool[pseg];
292 if(!--psegp->ref_cnt && !psegp->hardlock) {
293
294 remove_pseg_list(psegp);
295 add_to_used_pseg_list(psegp);
296 }
297 restore_flags(flags);
298 }
299
300
301
302
303 static inline void sun4c_unload_context_from_tlb(unsigned char ctx)
304 {
305 struct pseg_list *psegp, *pnextp;
306
307 if(pseg_count_per_context[ctx]) {
308 sun4c_flush_context();
309 psegp = s4cpseg_per_context[ctx].ctx_next;
310 while(psegp != &s4cpseg_per_context[ctx]) {
311 pnextp = psegp->ctx_next;
312 if(psegp->vaddr >= KERNBASE)
313 panic("Unloading kernel from tlb, not good.");
314 put_segmap(psegp->vaddr, invalid_segment);
315 remove_pseg_ctxlist(psegp, ctx);
316 remove_pseg_list(psegp);
317 add_to_free_pseg_list(psegp);
318 psegp = pnextp;
319 }
320 if(pseg_count_per_context[ctx])
321 panic("pseg_count_per_context inconsistant after "
322 "invalidate.");
323 }
324 }
325
326
327 static inline void sun4c_unload_page_from_tlb(unsigned long addr,
328 struct task_struct *tsk)
329 {
330 unsigned char save_ctx;
331
332 if(tsk->tss.context != -1) {
333 save_ctx = get_context();
334 flush_user_windows();
335 set_context(tsk->tss.context);
336 sun4c_flush_page(addr);
337 put_pte(addr, 0);
338 set_context(save_ctx);
339 }
340 }
341
342
343
344
345
346
347
348 void sun4c_invalidate(void)
349 {
350 int orig_ctx, cur_ctx, flags;
351
352 save_flags(flags); cli();
353 flush_user_windows();
354 orig_ctx = get_context();
355 for(cur_ctx = 0; cur_ctx < num_contexts; cur_ctx++) {
356 set_context(cur_ctx);
357 sun4c_unload_context_from_tlb(cur_ctx);
358 }
359 set_context(orig_ctx);
360 restore_flags(flags);
361 }
362
363
364 void sun4c_set_pte(pte_t *ptep, pte_t pteval)
365 {
366 *ptep = pteval;
367 }
368
369
370
371
372
373
374
375 void sun4c_pte_free_kernel(pte_t *pte)
376 {
377 mem_map[MAP_NR(pte)].reserved = 0;
378 free_page((unsigned long) pte);
379 }
380
381 pte_t *sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
382 {
383 address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
384 if (sun4c_pmd_none(*pmd)) {
385 pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
386 if (sun4c_pmd_none(*pmd)) {
387 if (page) {
388 pmd_val(*pmd) = PGD_TABLE | (unsigned long) page;
389 mem_map[MAP_NR(page)].reserved = 1;
390 return page + address;
391 }
392 pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
393 return NULL;
394 }
395 free_page((unsigned long) page);
396 }
397 if (sun4c_pmd_bad(*pmd)) {
398 printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
399 pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
400 return NULL;
401 }
402 return (pte_t *) sun4c_pmd_page(*pmd) + address;
403 }
404
405
406
407
408
409 void sun4c_pmd_free_kernel(pmd_t *pmd)
410 {
411 pmd_val(*pmd) = 0;
412 }
413
414 pmd_t *sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
415 {
416 return (pmd_t *) pgd;
417 }
418
419 void sun4c_pte_free(pte_t *pte)
420 {
421 free_page((unsigned long) pte);
422 }
423
424 pte_t *sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
425 {
426 address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
427 if (sun4c_pmd_none(*pmd)) {
428 pte_t *page = (pte_t *) get_free_page(GFP_KERNEL);
429 if (sun4c_pmd_none(*pmd)) {
430 if (page) {
431 pmd_val(*pmd) = PGD_TABLE | (unsigned long) page;
432 return page + address;
433 }
434 pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
435 return NULL;
436 }
437 free_page((unsigned long) page);
438 }
439 if (sun4c_pmd_bad(*pmd)) {
440 printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
441 pmd_val(*pmd) = PGD_TABLE | (unsigned long) BAD_PAGETABLE;
442 return NULL;
443 }
444 return (pte_t *) sun4c_pmd_page(*pmd) + address;
445 }
446
447
448
449
450
451 void sun4c_pmd_free(pmd_t * pmd)
452 {
453 pmd_val(*pmd) = 0;
454 }
455
456 pmd_t *sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
457 {
458 return (pmd_t *) pgd;
459 }
460
461 void sun4c_pgd_free(pgd_t *pgd)
462 {
463 free_page((unsigned long) pgd);
464 }
465
466 pgd_t *sun4c_pgd_alloc(void)
467 {
468 unsigned long new_pgd = get_free_page(GFP_KERNEL);
469 return (pgd_t *) new_pgd;
470 }
471
472
473
474
475 void sun4c_switch_to_context(void *new_task)
476 {
477 struct task_struct *tsk = (struct task_struct *) new_task;
478 struct task_struct *old_tsk;
479 struct ctx_list *ctxp;
480 unsigned long flags;
481 int ctx = tsk->tss.context;
482
483
484
485
486
487 if(tsk->pid == 0 || ctx != -1)
488 return;
489 ctxp = ctx_free.next;
490 if(ctxp != &ctx_free) {
491 save_flags(flags); cli();
492 ctx = ctxp->ctx_number;
493 remove_from_ctx_list(ctxp);
494 add_to_used_ctxlist(ctxp);
495 tsk->tss.context = ctx;
496 ctxp->ctx_task = tsk;
497 restore_flags(flags);
498 return;
499 }
500 save_flags(flags); cli();
501 ctxp = ctx_used.prev;
502
503 if(ctxp->ctx_task == current)
504 ctxp = ctxp->prev;
505 if(ctxp == &ctx_used)
506 panic("out of contexts");
507 remove_from_ctx_list(ctxp);
508 old_tsk = ctxp->ctx_task;
509 old_tsk->tss.context = -1;
510 ctxp->ctx_task = tsk;
511 tsk->tss.context = ctxp->ctx_number;
512 add_to_used_ctxlist(ctxp);
513
514 set_context(ctxp->ctx_number);
515 sun4c_unload_context_from_tlb(ctxp->ctx_number);
516 restore_flags(flags);
517 }
518
519
520
521
522
523 void sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
524 int bus_type, int rdonly)
525 {
526 unsigned long page_entry;
527
528 page_entry = ((physaddr >> PAGE_SHIFT) & 0xffff);
529 page_entry |= (_SUN4C_PAGE_VALID | _SUN4C_PAGE_WRITE |
530 _SUN4C_PAGE_NOCACHE | _SUN4C_PAGE_IO);
531 if(rdonly)
532 page_entry &= (~_SUN4C_PAGE_WRITE);
533 sun4c_flush_page(virt_addr);
534 put_pte(virt_addr, page_entry);
535 }
536
537
538
539
540
541 inline char *sun4c_lockarea(char *vaddr, unsigned long size)
542 {
543 unsigned long flags;
544 unsigned long orig_addr = (unsigned long) vaddr;
545 unsigned long first_seg = (orig_addr & SUN4C_REAL_PGDIR_MASK);
546 unsigned long last_seg = ((orig_addr + size) & SUN4C_REAL_PGDIR_MASK);
547
548 save_flags(flags); cli();
549 for(; first_seg <= last_seg; first_seg += SUN4C_REAL_PGDIR_SIZE)
550 sun4c_lock_tlb_entry(first_seg);
551
552 restore_flags(flags);
553 return vaddr;
554 }
555
556
557
558
559 inline void sun4c_unlockarea(char *vaddr, unsigned long size)
560 {
561 unsigned long flags;
562 unsigned long orig_addr = (unsigned long) vaddr;
563 unsigned long first_seg = (orig_addr & SUN4C_REAL_PGDIR_MASK);
564 unsigned long last_seg = ((orig_addr + size) & SUN4C_REAL_PGDIR_MASK);
565
566 save_flags(flags); cli();
567 for(; first_seg <= last_seg; first_seg += SUN4C_REAL_PGDIR_SIZE)
568 sun4c_unlock_tlb_entry(first_seg);
569
570 restore_flags(flags);
571 }
572
573
574 char *sun4c_get_scsi_buffer(char *bufptr, unsigned long len)
575 {
576 unsigned long first_page = ((unsigned long) bufptr) & PAGE_MASK;
577 unsigned long last_page = (((unsigned long) bufptr) + len) & PAGE_MASK;
578
579
580 bufptr = sun4c_lockarea(bufptr, len);
581
582
583 for(; first_page <= last_page; first_page += PAGE_SIZE) {
584 sun4c_flush_page(first_page);
585 put_pte(first_page, get_pte(first_page) | PTE_NC);
586 }
587 return bufptr;
588 }
589
590 void sun4c_release_scsi_buffer(char *bufptr, unsigned long len)
591 {
592 unsigned long first_page = ((unsigned long) bufptr) & PAGE_MASK;
593 unsigned long last_page = (((unsigned long) bufptr) + len) & PAGE_MASK;
594
595
596
597 for(; first_page <= last_page; first_page += PAGE_SIZE)
598 put_pte(first_page, get_pte(first_page) & ~PTE_NC);
599
600 sun4c_unlockarea(bufptr, len);
601 }
602
603
604 int sun4c_get_fault_info(unsigned long *address, unsigned long *error_code,
605 unsigned long from_user)
606 {
607 unsigned long faddr, fstatus, new_code;
608
609 faddr = sun4c_get_synchronous_address();
610 *address = faddr;
611 if(faddr >= 0x20000000 && faddr < 0xe0000000) {
612 printk("SUN4C: Fault in vm hole at %08lx\n", faddr);
613 *error_code = from_user;
614 return 1;
615 }
616 fstatus = sun4c_get_synchronous_error();
617 if(fstatus & SUN4C_SYNC_BOLIXED)
618 panic("SUN4C: Unrecoverable fault type.");
619 new_code = 0;
620 if(fstatus & SUN4C_SYNC_PROT)
621 new_code |= FAULT_CODE_PROT;
622 if(fstatus & SUN4C_SYNC_BADWRITE)
623 new_code |= FAULT_CODE_WRITE;
624 *error_code = (new_code | from_user);
625 return 0;
626 }
627
628 static inline void sun4c_alloc_pseg(unsigned long address)
629 {
630 struct pseg_list *psegp;
631 unsigned char cur_ctx = get_context();
632 int kernel_address = (address >= KERNBASE);
633 int user_address = !kernel_address;
634
635 psegp = s4cpseg_free.next;
636 if(psegp != &s4cpseg_free) {
637 remove_pseg_list(psegp);
638 add_to_used_pseg_list(psegp);
639 if(user_address)
640 add_pseg_ctxlist(psegp, cur_ctx);
641 psegp->vaddr = address;
642 psegp->context = cur_ctx;
643
644 if(kernel_address)
645 sun4c_distribute_kernel_mapping(address, psegp->pseg);
646 else
647 put_segmap(address, psegp->pseg);
648 return;
649 }
650 psegp = s4cpseg_used.prev;
651 if(psegp == &s4cpseg_used)
652 panic("Sun4c psegs have disappeared...");
653 if(psegp->vaddr >= KERNBASE) {
654 sun4c_delete_kernel_mapping(psegp->vaddr);
655 } else {
656 flush_user_windows();
657 set_context(psegp->context);
658 sun4c_flush_segment(psegp->vaddr);
659 put_segmap(psegp->vaddr, invalid_segment);
660 set_context(cur_ctx);
661 }
662 remove_pseg_list(psegp);
663 if(psegp->vaddr < KERNBASE)
664 remove_pseg_ctxlist(psegp, psegp->context);
665 psegp->vaddr = address;
666 psegp->context = cur_ctx;
667 if(kernel_address)
668 sun4c_distribute_kernel_mapping(address, psegp->pseg);
669 else
670 put_segmap(address, psegp->pseg);
671 add_to_used_pseg_list(psegp);
672 if(user_address)
673 add_pseg_ctxlist(psegp, cur_ctx);
674 }
675
676
677
678
679
680
681 void sun4c_update_mmu_cache(struct vm_area_struct * vma,
682 unsigned long address, pte_t pte)
683 {
684 unsigned long flags, segmap, segaddr, clean;
685
686 save_flags(flags); cli();
687 address &= PAGE_MASK;
688 segaddr = address & SUN4C_REAL_PGDIR_MASK;
689 segmap = get_segmap(segaddr);
690 if(segmap == invalid_segment) {
691 sun4c_alloc_pseg(segaddr);
692
693 for(clean = segaddr; clean < (segaddr + SUN4C_REAL_PGDIR_SIZE);
694 clean += PAGE_SIZE)
695 put_pte(clean, 0);
696 }
697
698
699
700
701
702 if(address < TASK_SIZE)
703 put_pte(address, pte_val(pte));
704 else {
705
706 pgd_t *pgdp;
707 pte_t *ptable;
708 int pnum = 64;
709
710 pgdp = sun4c_pgd_offset(&init_mm, segaddr);
711 ptable = sun4c_pte_offset((pmd_t *)pgdp, segaddr);
712 while(pnum--) {
713 put_pte(segaddr, pte_val(*ptable++));
714 segaddr += PAGE_SIZE;
715 };
716 }
717 restore_flags(flags);
718 }
719
720
721 static inline void sun4c_free_all_nonlocked_psegs(void)
722 {
723 struct pseg_list *plp;
724 int i;
725
726 for(i=0; i < invalid_segment; i++)
727 if(!s4cpseg_pool[i].hardlock)
728 add_to_free_pseg_list(&s4cpseg_pool[i]);
729
730 plp = s4cpseg_free.next;
731 while(plp != &s4cpseg_free) {
732 put_segmap(0x0, plp->pseg);
733 for(i=0; i<64; i++)
734 put_pte((i * PAGE_SIZE), 0x0);
735 plp = plp->next;
736 }
737 put_segmap(0x0, invalid_segment);
738 }
739
740 static inline struct pseg_list *sun4c_alloc_pseg_from_free_list(void)
741 {
742 struct pseg_list *psegp;
743
744 psegp = s4cpseg_free.next;
745 if(psegp != &s4cpseg_free) {
746 remove_pseg_list(psegp);
747 return psegp;
748 }
749 return 0;
750 }
751
752 static inline void sun4c_init_lock_area(unsigned long start_addr,
753 unsigned long end_addr)
754 {
755 struct pseg_list *psegp;
756 unsigned long a;
757 int ctx;
758
759 for(a = start_addr; a < end_addr; a += SUN4C_REAL_PGDIR_SIZE) {
760 psegp = sun4c_alloc_pseg_from_free_list();
761 if(!psegp) {
762 prom_printf("whoops...");
763 prom_halt();
764 }
765 for(ctx=0;ctx<num_contexts;ctx++)
766 prom_putsegment(ctx,a,psegp->pseg);
767 add_to_locked_pseg_list(psegp);
768 psegp->hardlock = 1;
769 }
770 }
771
772 static inline void sun4c_check_for_ss2_cache_bug(void)
773 {
774 extern unsigned long start;
775
776
777
778
779
780
781
782
783
784
785
786 if(idprom->id_machtype == (SM_SUN4C | SM_4C_SS2)) {
787
788 printk("SS2 cache bug detected, uncaching trap table page\n");
789 sun4c_flush_page((unsigned int) &start);
790 put_pte(((unsigned long) &start),
791 (get_pte((unsigned long) &start) | PTE_NC));
792 }
793 }
794
795 extern unsigned long free_area_init(unsigned long, unsigned long);
796
797
798 extern unsigned long end;
799 extern void probe_mmu(void);
800
801 unsigned long sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
802 {
803 unsigned long addr, vaddr, kern_begin, kern_end;
804 unsigned long prom_begin, prom_end, kadb_begin;
805 pgd_t *pgdp;
806 pte_t *pg_table;
807 int phys_seg, i, ctx;
808
809 start_mem = PAGE_ALIGN(start_mem);
810
811 probe_mmu();
812 invalid_segment = (num_segmaps - 1);
813 sun4c_init_pseg_lists();
814 for(kern_begin = KERNBASE;
815 kern_begin < (unsigned long) &end;
816 kern_begin += SUN4C_REAL_PGDIR_SIZE) {
817 unsigned char pseg = get_segmap(kern_begin);
818
819 s4cpseg_pool[pseg].hardlock=1;
820 for(ctx=0; ctx<num_contexts;ctx++)
821 prom_putsegment(ctx,kern_begin,pseg);
822 }
823 for(kern_begin = SUN4C_REAL_PGDIR_ALIGN((unsigned long) &end);
824 kern_begin < KADB_DEBUGGER_BEGVM;
825 kern_begin += SUN4C_REAL_PGDIR_SIZE)
826 for(ctx=0; ctx<num_contexts;ctx++)
827 prom_putsegment(ctx, kern_begin, invalid_segment);
828 for(prom_begin = KADB_DEBUGGER_BEGVM;
829 prom_begin < LINUX_OPPROM_ENDVM;
830 prom_begin += SUN4C_REAL_PGDIR_SIZE) {
831 unsigned long pseg = get_segmap(prom_begin);
832
833 if(pseg != invalid_segment) {
834 s4cpseg_pool[pseg].hardlock=1;
835 for(ctx=0; ctx<num_contexts; ctx++)
836 prom_putsegment(ctx,prom_begin,pseg);
837 }
838 }
839
840 for(ctx=0; ctx<num_contexts;ctx++) {
841 set_context(ctx);
842 for(vaddr = 0; vaddr < 0x20000000;
843 vaddr += SUN4C_REAL_PGDIR_SIZE)
844 put_segmap(vaddr,invalid_segment);
845 for(vaddr = 0xe0000000; vaddr < KERNBASE;
846 vaddr += SUN4C_REAL_PGDIR_SIZE)
847 put_segmap(vaddr,invalid_segment);
848 for(vaddr = LINUX_OPPROM_ENDVM; vaddr != 0;
849 vaddr += SUN4C_REAL_PGDIR_SIZE)
850 put_segmap(vaddr,invalid_segment);
851 }
852 set_context(0);
853 sun4c_free_all_nonlocked_psegs();
854
855 sun4c_init_lock_area(IOBASE_VADDR, IOBASE_END);
856 sun4c_init_lock_area(DVMA_VADDR, DVMA_END);
857
858 memset(swapper_pg_dir, 0, PAGE_SIZE);
859 memset(pg0, 0, PAGE_SIZE);
860
861 pgd_val(swapper_pg_dir[KERNBASE>>SUN4C_PGDIR_SHIFT]) =
862 PGD_TABLE | (unsigned long) pg0;
863
864
865
866
867
868
869
870
871 pgdp = swapper_pg_dir;
872 kern_end = PAGE_ALIGN(end_mem);
873 kern_begin = KERNBASE;
874 while(kern_begin < kern_end) {
875 unsigned long pte, tmp;
876
877
878 pg_table = (pte_t *) (PAGE_MASK & pgd_val(pgdp[KERNBASE>>SUN4C_PGDIR_SHIFT]));
879 if(!pg_table) {
880 pg_table = (pte_t *) start_mem;
881 start_mem += PAGE_SIZE;
882 }
883 pgd_val(pgdp[KERNBASE>>SUN4C_PGDIR_SHIFT]) =
884 PGD_TABLE | (unsigned long) pg_table;
885 pgdp++;
886 for(tmp = 0; tmp < SUN4C_PTRS_PER_PTE; tmp++, pg_table++) {
887 if(kern_begin < kern_end)
888 sun4c_set_pte(pg_table,
889 mk_pte(kern_begin,
890 SUN4C_PAGE_SHARED));
891 else
892 sun4c_pte_clear(pg_table);
893 pte = get_pte(kern_begin);
894 if(pte & _SUN4C_PAGE_VALID) {
895 pte &= ~(_SUN4C_PAGE_NOCACHE);
896 pte |= (_SUN4C_PAGE_PRIV | _SUN4C_PAGE_WRITE |
897 _SUN4C_PAGE_REF | _SUN4C_PAGE_DIRTY);
898 put_pte(kern_begin, pte);
899 }
900 kern_begin += PAGE_SIZE;
901 }
902 }
903 sun4c_check_for_ss2_cache_bug();
904
905 kadb_begin = KADB_DEBUGGER_BEGVM;
906 prom_end = LINUX_OPPROM_ENDVM;
907 for(; kadb_begin < prom_end; kadb_begin += PAGE_SIZE) {
908 unsigned long pte = get_pte(kadb_begin);
909 if(pte & _SUN4C_PAGE_VALID)
910 put_pte(kadb_begin, (pte | _SUN4C_PAGE_PRIV));
911 }
912
913 addr = DVMA_VADDR;
914 start_mem = PAGE_ALIGN(start_mem);
915 while(addr < DVMA_END) {
916 unsigned long dvmapte = start_mem - PAGE_OFFSET;
917
918 start_mem += PAGE_SIZE;
919 dvmapte = ((dvmapte>>PAGE_SHIFT) & 0xffff);
920 dvmapte |= (_SUN4C_PAGE_VALID |
921 _SUN4C_PAGE_WRITE |
922 _SUN4C_PAGE_NOCACHE);
923 put_pte(addr, dvmapte);
924 addr += PAGE_SIZE;
925 }
926
927 for(phys_seg=0, i=0; i<=invalid_segment; i++)
928 if(s4cpseg_pool[i].hardlock)
929 phys_seg++;
930 printk("SUN4C: Hard locked %d boot-up psegs\n", phys_seg);
931
932 ctx_list_pool = (struct ctx_list *) start_mem;
933 start_mem += (num_contexts * sizeof(struct ctx_list));
934 for(ctx = 0; ctx < num_contexts; ctx++) {
935 struct ctx_list *clist;
936
937 clist = (ctx_list_pool + ctx);
938 clist->ctx_number = ctx;
939 clist->ctx_task = 0;
940 }
941 ctx_free.next = ctx_free.prev = &ctx_free;
942 ctx_used.next = ctx_used.prev = &ctx_used;
943 for(ctx = 0; ctx < num_contexts; ctx++)
944 add_to_free_ctxlist(ctx_list_pool + ctx);
945 start_mem = PAGE_ALIGN(start_mem);
946 start_mem = free_area_init(start_mem, end_mem);
947 start_mem = PAGE_ALIGN(start_mem);
948 return start_mem;
949 }
950
951
952 void sun4c_test_wp(void)
953 {
954 wp_works_ok = -1;
955
956
957 put_pte((unsigned long) 0x0, (PTE_V | PTE_P));
958 __asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory");
959 put_pte((unsigned long) 0x0, 0x0);
960 if (wp_works_ok < 0)
961 wp_works_ok = 0;
962 }
963
964 void sun4c_lock_entire_kernel(unsigned long start_mem)
965 {
966 unsigned long addr = (unsigned long) &end;
967
968 addr = (addr & SUN4C_REAL_PGDIR_MASK);
969 start_mem = SUN4C_REAL_PGDIR_ALIGN(start_mem);
970 while(addr < start_mem) {
971 int pseg;
972
973 sun4c_lock_tlb_entry(addr);
974 pseg = get_segmap(addr);
975 if(!s4cpseg_pool[pseg].hardlock) {
976 s4cpseg_pool[pseg].hardlock = 1;
977 remove_pseg_list(&s4cpseg_pool[pseg]);
978 }
979 addr += SUN4C_REAL_PGDIR_SIZE;
980 }
981 }
982
983 static void sun4c_fork_hook(void *vtask, unsigned long kthread_usp)
984 {
985 struct task_struct *new_task = vtask;
986
987
988
989
990
991 sun4c_lock_tlb_entry((unsigned long) new_task);
992 sun4c_lock_tlb_entry(new_task->kernel_stack_page);
993 if(kthread_usp)
994 sun4c_lock_tlb_entry(kthread_usp);
995 }
996
997 static void sun4c_release_hook(void *vtask)
998 {
999 struct task_struct *old_task = vtask;
1000 struct ctx_list *ctx_old;
1001 struct pt_regs *regs;
1002 unsigned char this_ctx = get_context();
1003 unsigned long flags;
1004
1005 save_flags(flags); cli();
1006 if(old_task == &init_task)
1007 panic("AIEEE releasing swapper");
1008 if(old_task->tss.context != -1) {
1009
1010
1011 flush_user_windows();
1012 set_context(old_task->tss.context);
1013 sun4c_unload_context_from_tlb(old_task->tss.context);
1014 set_context(this_ctx);
1015
1016 ctx_old = ctx_list_pool + old_task->tss.context;
1017 remove_from_ctx_list(ctx_old);
1018 add_to_free_ctxlist(ctx_old);
1019 old_task->tss.context = -1;
1020 }
1021 regs = (struct pt_regs *)
1022 (((old_task->tss.ksp & ~0xfff)) + (0x1000 - TRACEREG_SZ));
1023 if(regs->u_regs[UREG_FP] > KERNBASE)
1024 sun4c_unlock_tlb_entry(regs->u_regs[UREG_FP] & PAGE_MASK);
1025 sun4c_unlock_tlb_entry(old_task->kernel_stack_page);
1026 sun4c_unlock_tlb_entry((unsigned long) old_task);
1027 restore_flags(flags);
1028
1029 }
1030
1031 static void sun4c_flush_hook(void *vtask)
1032 {
1033 struct task_struct *dead_task = vtask;
1034
1035 if(dead_task->tss.context != -1)
1036 sun4c_flush_context();
1037 }
1038
1039 static void sun4c_task_cacheflush(void *vtask)
1040 {
1041 struct task_struct *flush_task = vtask;
1042
1043 if(flush_task->tss.context != -1)
1044 sun4c_flush_context();
1045 }
1046
1047 static void sun4c_exit_hook(void *vtask)
1048 {
1049 }
1050
1051
1052 void ld_mmu_sun4c(void)
1053 {
1054 printk("Loading sun4c MMU routines\n");
1055
1056
1057 pmd_shift = SUN4C_PMD_SHIFT;
1058 pmd_size = SUN4C_PMD_SIZE;
1059 pmd_mask = SUN4C_PMD_MASK;
1060 pgdir_shift = SUN4C_PGDIR_SHIFT;
1061 pgdir_size = SUN4C_PGDIR_SIZE;
1062 pgdir_mask = SUN4C_PGDIR_MASK;
1063
1064 ptrs_per_pte = SUN4C_PTRS_PER_PTE;
1065 ptrs_per_pmd = SUN4C_PTRS_PER_PMD;
1066 ptrs_per_pgd = SUN4C_PTRS_PER_PGD;
1067
1068 page_none = SUN4C_PAGE_NONE;
1069 page_shared = SUN4C_PAGE_SHARED;
1070 page_copy = SUN4C_PAGE_COPY;
1071 page_readonly = SUN4C_PAGE_READONLY;
1072 page_kernel = SUN4C_PAGE_KERNEL;
1073 page_invalid = SUN4C_PAGE_INVALID;
1074
1075
1076 invalidate = sun4c_invalidate;
1077 set_pte = sun4c_set_pte;
1078 switch_to_context = sun4c_switch_to_context;
1079 pmd_align = sun4c_pmd_align;
1080 pgdir_align = sun4c_pgdir_align;
1081 vmalloc_start = sun4c_vmalloc_start;
1082
1083 pte_page = sun4c_pte_page;
1084 pmd_page = sun4c_pmd_page;
1085
1086 sparc_update_rootmmu_dir = sun4c_update_rootmmu_dir;
1087
1088 pte_none = sun4c_pte_none;
1089 pte_present = sun4c_pte_present;
1090 pte_inuse = sun4c_pte_inuse;
1091 pte_clear = sun4c_pte_clear;
1092 pte_reuse = sun4c_pte_reuse;
1093
1094 pmd_none = sun4c_pmd_none;
1095 pmd_bad = sun4c_pmd_bad;
1096 pmd_present = sun4c_pmd_present;
1097 pmd_inuse = sun4c_pmd_inuse;
1098 pmd_clear = sun4c_pmd_clear;
1099 pmd_reuse = sun4c_pmd_reuse;
1100
1101 pgd_none = sun4c_pgd_none;
1102 pgd_bad = sun4c_pgd_bad;
1103 pgd_present = sun4c_pgd_present;
1104 pgd_inuse = sun4c_pgd_inuse;
1105 pgd_clear = sun4c_pgd_clear;
1106
1107 mk_pte = sun4c_mk_pte;
1108 pte_modify = sun4c_pte_modify;
1109 pgd_offset = sun4c_pgd_offset;
1110 pmd_offset = sun4c_pmd_offset;
1111 pte_offset = sun4c_pte_offset;
1112 pte_free_kernel = sun4c_pte_free_kernel;
1113 pmd_free_kernel = sun4c_pmd_free_kernel;
1114 pte_alloc_kernel = sun4c_pte_alloc_kernel;
1115 pmd_alloc_kernel = sun4c_pmd_alloc_kernel;
1116 pte_free = sun4c_pte_free;
1117 pte_alloc = sun4c_pte_alloc;
1118 pmd_free = sun4c_pmd_free;
1119 pmd_alloc = sun4c_pmd_alloc;
1120 pgd_free = sun4c_pgd_free;
1121 pgd_alloc = sun4c_pgd_alloc;
1122
1123 pte_read = sun4c_pte_read;
1124 pte_write = sun4c_pte_write;
1125 pte_exec = sun4c_pte_exec;
1126 pte_dirty = sun4c_pte_dirty;
1127 pte_young = sun4c_pte_young;
1128 pte_cow = sun4c_pte_cow;
1129 pte_wrprotect = sun4c_pte_wrprotect;
1130 pte_rdprotect = sun4c_pte_rdprotect;
1131 pte_exprotect = sun4c_pte_exprotect;
1132 pte_mkclean = sun4c_pte_mkclean;
1133 pte_mkold = sun4c_pte_mkold;
1134 pte_uncow = sun4c_pte_uncow;
1135 pte_mkwrite = sun4c_pte_mkwrite;
1136 pte_mkread = sun4c_pte_mkread;
1137 pte_mkexec = sun4c_pte_mkexec;
1138 pte_mkdirty = sun4c_pte_mkdirty;
1139 pte_mkyoung = sun4c_pte_mkyoung;
1140 pte_mkcow = sun4c_pte_mkcow;
1141 get_fault_info = sun4c_get_fault_info;
1142 update_mmu_cache = sun4c_update_mmu_cache;
1143 mmu_exit_hook = sun4c_exit_hook;
1144 mmu_fork_hook = sun4c_fork_hook;
1145 mmu_release_hook = sun4c_release_hook;
1146 mmu_flush_hook = sun4c_flush_hook;
1147 mmu_task_cacheflush = sun4c_task_cacheflush;
1148 mmu_lockarea = sun4c_lockarea;
1149 mmu_unlockarea = sun4c_unlockarea;
1150 mmu_get_scsi_buffer = sun4c_get_scsi_buffer;
1151 mmu_release_scsi_buffer = sun4c_release_scsi_buffer;
1152
1153
1154 pgd_set = 0;
1155 pgd_reuse = 0;
1156 pgd_page = 0;
1157 }