root/arch/sparc/mm/sun4c.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun4c_pmd_align
  2. sun4c_pgdir_align
  3. sun4c_virt_to_phys
  4. sun4c_phys_to_virt
  5. sun4c_vmalloc_start
  6. sun4c_pte_page
  7. sun4c_pmd_page
  8. sun4c_pgd_page
  9. sun4c_update_rootmmu_dir
  10. sun4c_pte_none
  11. sun4c_pte_present
  12. sun4c_pte_inuse
  13. sun4c_pte_clear
  14. sun4c_pte_reuse
  15. sun4c_pmd_none
  16. sun4c_pmd_bad
  17. sun4c_pmd_present
  18. sun4c_pmd_inuse
  19. sun4c_pmd_clear
  20. sun4c_pmd_reuse
  21. sun4c_pgd_none
  22. sun4c_pgd_bad
  23. sun4c_pgd_present
  24. sun4c_pgd_inuse
  25. sun4c_pgd_clear
  26. sun4c_pgd_reuse
  27. sun4c_pte_read
  28. sun4c_pte_write
  29. sun4c_pte_exec
  30. sun4c_pte_dirty
  31. sun4c_pte_young
  32. sun4c_pte_cow
  33. sun4c_pte_wrprotect
  34. sun4c_pte_rdprotect
  35. sun4c_pte_exprotect
  36. sun4c_pte_mkclean
  37. sun4c_pte_mkold
  38. sun4c_pte_uncow
  39. sun4c_pte_mkwrite
  40. sun4c_pte_mkread
  41. sun4c_pte_mkexec
  42. sun4c_pte_mkdirty
  43. sun4c_pte_mkyoung
  44. sun4c_pte_mkcow
  45. sun4c_mk_pte
  46. sun4c_pgd_set
  47. sun4c_pte_modify
  48. sun4c_pgd_offset
  49. sun4c_pmd_offset
  50. sun4c_pte_offset
  51. sun4c_pte_free_kernel
  52. sun4c_pmd_set
  53. sun4c_pte_alloc_kernel
  54. sun4c_pmd_free_kernel
  55. sun4c_pmd_alloc_kernel
  56. sun4c_pte_free
  57. sun4c_pte_alloc
  58. sun4c_pmd_free
  59. sun4c_pmd_alloc
  60. sun4c_pgd_free
  61. sun4c_pgd_alloc
  62. sun4c_invalidate
  63. sun4c_set_pte
  64. sun4c_switch_to_context
  65. sun4c_get_context
  66. sun4c_mapioaddr
  67. sun4c_paging_init
  68. sun4c_test_wp
  69. ld_mmu_sun4c

   1 /* sun4c.c:  Sun4C specific mm routines.
   2  *
   3  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
   4  */
   5 
   6 /* The SUN4C has an MMU based upon a Translation Lookaside Buffer scheme
   7  * where only so many translations can be loaded at once.  As Linus said
   8  * in Boston, this is a broken way of doing things.
   9  *
  10  * NOTE:  Free page pool and tables now live in high memory, see
  11  *        asm-sparc/pgtsun4c.c and asm-sparc/page.h for details.
  12  */
  13 
  14 #include <linux/kernel.h>  /* for printk */
  15 #include <linux/sched.h>
  16 
  17 #include <asm/processor.h> /* for wp_works_ok */
  18 #include <asm/page.h>
  19 #include <asm/pgtable.h>
  20 #include <asm/vac-ops.h>
  21 #include <asm/vaddrs.h>
  22 #include <asm/asi.h>
  23 #include <asm/contregs.h>
  24 #include <asm/kdebug.h>
  25 
  26 unsigned int sun4c_pmd_align(unsigned int addr) { return SUN4C_PMD_ALIGN(addr); }
     /* [previous][next][first][last][top][bottom][index][help] */
  27 unsigned int sun4c_pgdir_align(unsigned int addr) { return SUN4C_PGDIR_ALIGN(addr); }
     /* [previous][next][first][last][top][bottom][index][help] */
  28 
  29 extern int num_segmaps, num_contexts;
  30 
  31 /* Idea taken from Hamish McDonald's MC680x0 Linux code, nice job.
  32  * The only function that actually uses this is sun4c_mk_pte() and
  33  * to have a complete physical ram structure walk happen for each
  34  * invocation is quite costly.  However, this does do some nice
  35  * sanity checking and we'll see when our maps don't match.  Eventually
  36  * when I trust my code I will just do a direct mmu probe in mk_pte().
  37  */
  38 static inline unsigned int sun4c_virt_to_phys(unsigned int vaddr)
     /* [previous][next][first][last][top][bottom][index][help] */
  39 {
  40         unsigned int paddr = 0;
  41         unsigned int voff = (vaddr - PAGE_OFFSET);
  42         int i;
  43 
  44         for(i=0; sp_banks[i].num_bytes != 0; i++) {
  45                 if(voff < paddr + sp_banks[i].num_bytes) {
  46                         /* This matches. */
  47                         return sp_banks[i].base_addr + voff - paddr;
  48                 } else
  49                         paddr += sp_banks[i].num_bytes;
  50         }
  51         /* Shit, gotta consult the MMU, this shouldn't happen... */
  52         printk("sun4c_virt_to_phys: Could not make translation for vaddr %08lx\n", (unsigned long) vaddr);
  53         SP_ENTER_DEBUGGER;
  54 }               
  55 
  56 static inline unsigned long
  57 sun4c_phys_to_virt(unsigned long paddr)
     /* [previous][next][first][last][top][bottom][index][help] */
  58 {
  59         int i;
  60         unsigned long offset = PAGE_OFFSET;
  61 
  62         for (i=0; sp_banks[i].num_bytes != 0; i++)
  63         {
  64                 if (paddr >= sp_banks[i].base_addr &&
  65                     paddr < (sp_banks[i].base_addr
  66                              + sp_banks[i].num_bytes)) {
  67                         return (paddr - sp_banks[i].base_addr) + offset;
  68                 } else
  69                         offset += sp_banks[i].num_bytes;
  70         }
  71         printk("sun4c_phys_to_virt: Could not make translation for paddr %08lx\n", (unsigned long) paddr);
  72         SP_ENTER_DEBUGGER;
  73 }
  74 
  75 unsigned long
  76 sun4c_vmalloc_start(void)
     /* [previous][next][first][last][top][bottom][index][help] */
  77 {
  78         return ((high_memory + SUN4C_VMALLOC_OFFSET) & ~(SUN4C_VMALLOC_OFFSET-1));
  79 }
  80 
  81 /* Note that I have 16 page tables per page, thus four less
  82  * bits of shifting than normal.
  83  */
  84 
  85 unsigned long
  86 sun4c_pte_page(pte_t pte)
     /* [previous][next][first][last][top][bottom][index][help] */
  87 {
  88         unsigned long page;
  89 
  90         page = ((pte_val(pte) & _SUN4C_PFN_MASK) << (PAGE_SHIFT));
  91         return sun4c_phys_to_virt(page);
  92 }
  93 
  94 unsigned long 
  95 sun4c_pmd_page(pmd_t pmd)
     /* [previous][next][first][last][top][bottom][index][help] */
  96 {
  97         return ((pmd_val(pmd) & _SUN4C_PGD_PFN_MASK) << (_SUN4C_PGD_PAGE_SHIFT));
  98 }
  99 
 100 unsigned long
 101 sun4c_pgd_page(pgd_t pgd)
     /* [previous][next][first][last][top][bottom][index][help] */
 102 {
 103         return ((pgd_val(pgd) & _SUN4C_PGD_PFN_MASK) << (_SUN4C_PGD_PAGE_SHIFT));
 104 }
 105 
 106 /* Update the root mmu directory on the sun4c mmu. */
 107 void
 108 sun4c_update_rootmmu_dir(struct task_struct *tsk, pgd_t *pgdir)
     /* [previous][next][first][last][top][bottom][index][help] */
 109 {
 110         (tsk)->tss.pgd_ptr = (unsigned long) (pgdir);
 111 
 112         /* May have to do some flushing here. */
 113 
 114         return;
 115 }
 116 
 117 int sun4c_pte_none(pte_t pte)           { return !pte_val(pte); }
     /* [previous][next][first][last][top][bottom][index][help] */
 118 int sun4c_pte_present(pte_t pte)        { return pte_val(pte) & _SUN4C_PAGE_VALID; }
     /* [previous][next][first][last][top][bottom][index][help] */
 119 int sun4c_pte_inuse(pte_t *ptep)        { return mem_map[MAP_NR(ptep)] != 1; }
     /* [previous][next][first][last][top][bottom][index][help] */
 120 void sun4c_pte_clear(pte_t *ptep)       { pte_val(*ptep) = 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
 121 void sun4c_pte_reuse(pte_t *ptep)
     /* [previous][next][first][last][top][bottom][index][help] */
 122 {
 123   if(!(mem_map[MAP_NR(ptep)] & MAP_PAGE_RESERVED))
 124     mem_map[MAP_NR(ptep)]++;
 125 }
 126 
 127 int sun4c_pmd_none(pmd_t pmd)           { return !pmd_val(pmd); }
     /* [previous][next][first][last][top][bottom][index][help] */
 128 int sun4c_pmd_bad(pmd_t pmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 129 {
 130         return ((pmd_val(pmd) & _SUN4C_PGD_MMU_MASK) != _SUN4C_PAGE_TABLE);
 131 }
 132 
 133 int sun4c_pmd_present(pmd_t pmd)        { return pmd_val(pmd) & _SUN4C_PAGE_VALID; }
     /* [previous][next][first][last][top][bottom][index][help] */
 134 int sun4c_pmd_inuse(pmd_t *pmdp)        { return 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
 135 void sun4c_pmd_clear(pmd_t *pmdp)       { pmd_val(*pmdp) = 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
 136 void sun4c_pmd_reuse(pmd_t * pmdp)      { }
     /* [previous][next][first][last][top][bottom][index][help] */
 137 
 138 int sun4c_pgd_none(pgd_t pgd)           { return 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
 139 int sun4c_pgd_bad(pgd_t pgd)            { return 0; }
     /* [previous][next][first][last][top][bottom][index][help] */
 140 int sun4c_pgd_present(pgd_t pgd)        { return 1; }
     /* [previous][next][first][last][top][bottom][index][help] */
 141 int sun4c_pgd_inuse(pgd_t *pgdp)        { return mem_map[MAP_NR(pgdp)] != 1; }
     /* [previous][next][first][last][top][bottom][index][help] */
 142 void sun4c_pgd_clear(pgd_t * pgdp)      { }
     /* [previous][next][first][last][top][bottom][index][help] */
 143 void sun4c_pgd_reuse(pgd_t *pgdp)
     /* [previous][next][first][last][top][bottom][index][help] */
 144 {
 145   if (!(mem_map[MAP_NR(pgdp)] & MAP_PAGE_RESERVED))
 146     mem_map[MAP_NR(pgdp)]++;
 147 }
 148 
 149 /*
 150  * The following only work if pte_present() is true.
 151  * Undefined behaviour if not..
 152  */
 153 int sun4c_pte_read(pte_t pte)           { return pte_val(pte) & _SUN4C_PAGE_VALID; }
     /* [previous][next][first][last][top][bottom][index][help] */
 154 int sun4c_pte_write(pte_t pte)          { return pte_val(pte) & _SUN4C_PAGE_WRITE; }
     /* [previous][next][first][last][top][bottom][index][help] */
 155 int sun4c_pte_exec(pte_t pte)           { return pte_val(pte) & _SUN4C_PAGE_VALID; }
     /* [previous][next][first][last][top][bottom][index][help] */
 156 int sun4c_pte_dirty(pte_t pte)          { return pte_val(pte) & _SUN4C_PAGE_DIRTY; }
     /* [previous][next][first][last][top][bottom][index][help] */
 157 int sun4c_pte_young(pte_t pte)          { return pte_val(pte) & _SUN4C_PAGE_REF; }
     /* [previous][next][first][last][top][bottom][index][help] */
 158 int sun4c_pte_cow(pte_t pte)            { return pte_val(pte) & _SUN4C_PAGE_COW; }
     /* [previous][next][first][last][top][bottom][index][help] */
 159 
 160 pte_t sun4c_pte_wrprotect(pte_t pte)    { pte_val(pte) &= ~_SUN4C_PAGE_WRITE; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 161 pte_t sun4c_pte_rdprotect(pte_t pte)    { pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 162 pte_t sun4c_pte_exprotect(pte_t pte)    { pte_val(pte) |= _SUN4C_PAGE_PRIV; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 163 pte_t sun4c_pte_mkclean(pte_t pte)      { pte_val(pte) &= ~_SUN4C_PAGE_DIRTY; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 164 pte_t sun4c_pte_mkold(pte_t pte)        { pte_val(pte) &= ~_SUN4C_PAGE_REF; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 165 pte_t sun4c_pte_uncow(pte_t pte)        { pte_val(pte) &= ~_SUN4C_PAGE_COW; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 166 pte_t sun4c_pte_mkwrite(pte_t pte)      { pte_val(pte) |= _SUN4C_PAGE_WRITE; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 167 pte_t sun4c_pte_mkread(pte_t pte)       { pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 168 pte_t sun4c_pte_mkexec(pte_t pte)       { pte_val(pte) &= ~_SUN4C_PAGE_PRIV; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 169 pte_t sun4c_pte_mkdirty(pte_t pte)      { pte_val(pte) |= _SUN4C_PAGE_DIRTY; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 170 pte_t sun4c_pte_mkyoung(pte_t pte)      { pte_val(pte) |= _SUN4C_PAGE_REF; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 171 pte_t sun4c_pte_mkcow(pte_t pte)        { pte_val(pte) |= _SUN4C_PAGE_COW; return pte; }
     /* [previous][next][first][last][top][bottom][index][help] */
 172 
 173 /*
 174  * Conversion functions: convert a page and protection to a page entry,
 175  * and a page entry and page directory to the page they refer to.
 176  */
 177 pte_t
 178 sun4c_mk_pte(unsigned long page, pgprot_t pgprot)
     /* [previous][next][first][last][top][bottom][index][help] */
 179 {
 180         pte_t pte;
 181 
 182         if(page & (~PAGE_MASK)) panic("sun4c_mk_pte() called with unaligned page");
 183         page = sun4c_virt_to_phys(page);
 184         pte_val(pte) = ((page>>PAGE_SHIFT)&_SUN4C_PFN_MASK);
 185         pte_val(pte) |= (pgprot_val(pgprot) & _SUN4C_MMU_MASK);
 186         return pte;
 187 }
 188 
 189 void
 190 sun4c_pgd_set(pgd_t * pgdp, pte_t * ptep)
     /* [previous][next][first][last][top][bottom][index][help] */
 191 {
 192         pgd_val(*pgdp) = (_SUN4C_PAGE_TABLE & _SUN4C_PGD_MMU_MASK);
 193         pgd_val(*pgdp) |= (((((unsigned long) ptep)) >>
 194                             (_SUN4C_PGD_PAGE_SHIFT)) & _SUN4C_PGD_PFN_MASK);
 195 }
 196 
 197 pte_t
 198 sun4c_pte_modify(pte_t pte, pgprot_t newprot)
     /* [previous][next][first][last][top][bottom][index][help] */
 199 {
 200         pte_val(pte) = (pte_val(pte) & _SUN4C_PAGE_CHG_MASK);
 201         pte_val(pte) |= pgprot_val(newprot);
 202         return pte;
 203 }
 204 
 205 /* to find an entry in a page-table-directory */
 206 pgd_t *
 207 sun4c_pgd_offset(struct task_struct * tsk, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 208 {
 209         return ((pgd_t *) (tsk->tss.pgd_ptr)) +
 210                 (address >> SUN4C_PGDIR_SHIFT);
 211 }
 212 
 213 /* Find an entry in the second-level page table.. */
 214 pmd_t *
 215 sun4c_pmd_offset(pgd_t * dir, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217         return (pmd_t *) dir;
 218 }
 219 
 220 /* Find an entry in the third-level page table.. */ 
 221 pte_t *
 222 sun4c_pte_offset(pmd_t * dir, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 223 {
 224         return (pte_t *) sun4c_pmd_page(*dir) + ((address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1));
 225 }
 226 
 227 /*
 228  * Allocate and free page tables. The xxx_kernel() versions are
 229  * used to allocate a kernel page table - this turns on ASN bits
 230  * if any, and marks the page tables reserved.
 231  */
 232 void
 233 sun4c_pte_free_kernel(pte_t *pte)
     /* [previous][next][first][last][top][bottom][index][help] */
 234 {
 235         mem_map[MAP_NR(pte)] = 1;
 236         free_page((unsigned long) pte);
 237 }
 238 
 239 static inline void
 240 sun4c_pmd_set(pmd_t * pmdp, pte_t * ptep)
     /* [previous][next][first][last][top][bottom][index][help] */
 241 {
 242         pmd_val(*pmdp) = (_SUN4C_PAGE_TABLE & _SUN4C_PGD_MMU_MASK);
 243         pmd_val(*pmdp) |= ((((unsigned long) ptep) >> (_SUN4C_PGD_PAGE_SHIFT)) & _SUN4C_PGD_PFN_MASK);
 244 }
 245 
 246 
 247 pte_t *
 248 sun4c_pte_alloc_kernel(pmd_t *pmd, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 249 {
 250         pte_t *page;
 251 
 252 
 253         address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
 254         if (sun4c_pmd_none(*pmd)) {
 255                 /* New scheme, use a whole page */
 256                 page = (pte_t *) get_free_page(GFP_KERNEL);
 257                 if (sun4c_pmd_none(*pmd)) {
 258                         if (page) {
 259                                 sun4c_pmd_set(pmd, page);
 260                                 mem_map[MAP_NR(page)] = MAP_PAGE_RESERVED;
 261                                 return page + address;
 262                         }
 263                         sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
 264                         return NULL;
 265                 }
 266                 free_page((unsigned long) page);
 267         }
 268         if (sun4c_pmd_bad(*pmd)) {
 269                 printk("Bad pmd in pte_alloc_kernel: %08lx\n", pmd_val(*pmd));
 270                 sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
 271                 return NULL;
 272         }
 273 
 274         return (pte_t *) sun4c_pmd_page(*pmd) + address;
 275 }
 276 
 277 /*
 278  * allocating and freeing a pmd is trivial: the 1-entry pmd is
 279  * inside the pgd, so has no extra memory associated with it.
 280  */
 281 void
 282 sun4c_pmd_free_kernel(pmd_t *pmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 283 {
 284         return;
 285 }
 286 
 287 pmd_t *
 288 sun4c_pmd_alloc_kernel(pgd_t *pgd, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 289 {
 290         return (pmd_t *) pgd;
 291 }
 292 
 293 void
 294 sun4c_pte_free(pte_t *pte)
     /* [previous][next][first][last][top][bottom][index][help] */
 295 {
 296         free_page((unsigned long) pte);
 297 }
 298 
 299 pte_t *
 300 sun4c_pte_alloc(pmd_t * pmd, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 301 {
 302         pte_t *page;
 303 
 304         address = (address >> PAGE_SHIFT) & (SUN4C_PTRS_PER_PTE - 1);
 305         if (sun4c_pmd_none(*pmd)) {
 306                 page = (pte_t *) get_free_page(GFP_KERNEL);
 307                 if (sun4c_pmd_none(*pmd)) {
 308                         if (page) {
 309                                 sun4c_pmd_set(pmd, page);
 310                                 return page + address;
 311                         }
 312                         sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
 313                         return NULL;
 314                 }
 315                 free_page((unsigned long) page);
 316         }
 317         if (sun4c_pmd_bad(*pmd)) {
 318                 printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
 319                 sun4c_pmd_set(pmd, (pte_t *) BAD_PAGETABLE);
 320                 halt();
 321                 return NULL;
 322         }
 323 
 324         return (pte_t *) sun4c_pmd_page(*pmd) + address;
 325 }
 326 
 327 /*
 328  * allocating and freeing a pmd is trivial: the 1-entry pmd is
 329  * inside the pgd, so has no extra memory associated with it.
 330  */
 331 void 
 332 sun4c_pmd_free(pmd_t * pmd)
     /* [previous][next][first][last][top][bottom][index][help] */
 333 {
 334         return;
 335 }
 336 
 337 pmd_t *
 338 sun4c_pmd_alloc(pgd_t * pgd, unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 339 {
 340         return (pmd_t *) pgd;
 341 }
 342 
 343 /* This now works, as both our pgd's and pte's have 1024 entries. */
 344 void
 345 sun4c_pgd_free(pgd_t *pgd)
     /* [previous][next][first][last][top][bottom][index][help] */
 346 {
 347         free_page((unsigned long) pgd);
 348 }
 349 
 350 /* A page directory on the sun4c needs 64k, thus we request an order of
 351  * four.  We must also clear it by hand, very inefficient.
 352  */
 353 
 354 pgd_t *
 355 sun4c_pgd_alloc(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 356 {
 357         return (pgd_t *) get_free_page(GFP_KERNEL);
 358 }
 359 
 360 void
 361 sun4c_invalidate(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 362 {
 363         flush_vac_context();
 364 }
 365 
 366 void
 367 sun4c_set_pte(pte_t *ptep, pte_t entry)
     /* [previous][next][first][last][top][bottom][index][help] */
 368 {
 369         /* for now... */
 370         *ptep = entry;
 371 }
 372 
 373 void
 374 sun4c_switch_to_context(int context)
     /* [previous][next][first][last][top][bottom][index][help] */
 375 {
 376         __asm__ __volatile__("stba %0, [%1] %2" : :
 377                              "r" (context),
 378                              "r" (AC_CONTEXT), "i" (ASI_CONTROL));
 379 
 380         return;
 381 }
 382 
 383 int 
 384 sun4c_get_context(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 385 {
 386         register int ctx;
 387 
 388         __asm__ __volatile__("lduba [%1] %2, %0" :
 389                              "=r" (ctx) :
 390                              "r" (AC_CONTEXT), "i" (ASI_CONTROL));
 391 
 392         return ctx;
 393 }
 394 
 395 /* Low level IO area allocation on the Sun4c MMU.  This function is called
 396  * for each page of IO area you need.  Kernel code should not call this
 397  * routine directly, use sparc_alloc_io() instead.
 398  */
 399 void
 400 sun4c_mapioaddr(unsigned long physaddr, unsigned long virt_addr,
     /* [previous][next][first][last][top][bottom][index][help] */
 401                 int bus_type, int rdonly)
 402 {
 403   unsigned long page_entry;
 404 
 405   page_entry = ((physaddr >> PAGE_SHIFT) & _SUN4C_PFN_MASK);
 406 
 407   if(!rdonly)
 408           page_entry |= (PTE_V | PTE_ACC | PTE_NC | PTE_IO);  /* kernel io addr */
 409   else
 410           page_entry |= (PTE_V | PTE_P | PTE_NC | PTE_IO);  /* readonly io addr */
 411 
 412   page_entry &= (~PTE_RESV);
 413 
 414   /* Maybe have to do something with the bus_type on sun4c's? */
 415 
 416 
 417   put_pte(virt_addr, page_entry);
 418   return;
 419 }
 420 
 421 /* Paging initialization on the Sun4c. */
 422 extern unsigned long free_area_init(unsigned long, unsigned long);
 423 extern unsigned long eintstack, intstack;
 424 
 425 /* This code was soooo krufty, I have to rewrite this now! XXX
 426  * Ok, things are cleaning up.  I have now decided that it makes
 427  * a lot of sense to put the free page pool in upper ram right
 428  * after the kernel.  We map these free pages to be virtually
 429  * contiguous, that way we don't get so many reserved pages
 430  * during mem_init().  I think this will work out nicely.
 431  */
 432 extern unsigned long start;
 433 
 434 static unsigned long mempool;  /* This allows us to work with elf bootloaders */
 435 
 436 unsigned long
 437 sun4c_paging_init(unsigned long start_mem, unsigned long end_mem)
     /* [previous][next][first][last][top][bottom][index][help] */
 438 {
 439         unsigned long addr, vaddr, kern_begin, kern_end;
 440         unsigned long prom_begin, prom_end;
 441         int phys_seg, i, min_prom_segmap;
 442         pgd_t *pgdp;
 443         pmd_t *pmdp;
 444         pte_t *ptep;
 445 
 446         mempool = start_mem;
 447 
 448         /* 127 on most sun4c's, 255 on SS2 and IPX. */
 449         invalid_segment = (num_segmaps - 1);
 450 
 451         memset(swapper_pg_dir, 0, PAGE_SIZE);
 452         memset(pg0, 0, PAGE_SIZE);
 453         /* Delete low mapping of the kernel and sanitize invalid segmap. */
 454         for(vaddr=0; vaddr<(4*1024*1024); vaddr+=SUN4C_REAL_PGDIR_SIZE) 
 455                 put_segmap(vaddr, invalid_segment);
 456         for(vaddr=0; vaddr<(256*1024); vaddr+=PAGE_SIZE) put_pte(vaddr, 0);
 457 
 458         /* Initialize phys_seg_map[] */
 459         for(i=0; i<num_segmaps; i++) phys_seg_map[i] = PSEG_AVL;
 460         for(i=num_segmaps; i<PSEG_ENTRIES; i++) phys_seg_map[i] = PSEG_RSV;
 461 
 462         kern_begin = KERNBASE;
 463         kern_end = ((unsigned long) &end);
 464         prom_begin = LINUX_OPPROM_BEGVM;
 465         prom_end = LINUX_OPPROM_ENDVM;
 466 
 467         /* Set up swapper_pg_dir based upon three things:
 468          * 1) Where the kernel lives (KERNBASE)
 469          * 2) Where the PROM lives (PROM_BEGVM -> PROM_ENDVM)
 470          *    This is cheese, should do it dynamically XXX
 471          * 3) Where the valid physical pages are (sp_banks[])
 472          *    This is done first.
 473          *
 474          * I'm trying to concentrate this into one big loop and localize
 475          * the logic because it is so messy to do it in seperate loop
 476          * stages.  If anyone else has better ideas, let me know.
 477          */
 478 
 479         if(sp_banks[0].base_addr != 0)
 480                 panic("sun4c_paging_init: First physical address in first bank is not zero!\n");
 481         /* First, linearly map all physical RAM to the equivalent virtual pages.
 482          * Then, we invalidate everything the kernel uses by either invalidating
 483          * the entire segmep (if the whole segment is used by the kernel) or
 484          * just invalidating the relevant pte's.
 485          */
 486 
 487         for(vaddr = KERNBASE; vaddr < end_mem; vaddr+=PAGE_SIZE) {
 488                 pgdp = sun4c_pgd_offset(current, vaddr);
 489                 pmdp = sun4c_pmd_offset(pgdp, vaddr);
 490                 if(sun4c_pmd_none(*pmdp)) {
 491                         pgd_set(pgdp, (pte_t *) mempool);
 492                         mempool += PAGE_SIZE;
 493                 }
 494                 ptep = sun4c_pte_offset(pmdp, vaddr);
 495                 *ptep = sun4c_mk_pte(vaddr, SUN4C_PAGE_KERNEL);
 496         }
 497 
 498         /* Now map the kernel, and mark the segmaps as PSEG_KERN.
 499          *
 500          * NOTE: The first address of the upper kernel mapping must be
 501          *       segment aligned.
 502          */
 503         if(kern_begin & (~SUN4C_REAL_PGDIR_MASK)) {
 504                 panic("paging_init() Kernel not segmap aligned, halting...");
 505         }
 506 
 507         /* Mark the segmaps so that our phys_seg allocator doesn't try to
 508          * use them for TLB misses.
 509          */
 510         for(addr=kern_begin; addr < kern_end; addr += SUN4C_REAL_PGDIR_SIZE) {
 511                 if(get_segmap(addr) == invalid_segment) {
 512                         panic("paging_init() AIEEE, Kernel has invalid mapping, halting...");
 513                 }
 514                 phys_seg = get_segmap(addr);
 515                 phys_seg_map[phys_seg] = PSEG_KERNEL;
 516                 /* Map this segment in every context */
 517                 for(i=0; i<num_contexts; i++)
 518                         (*romvec->pv_setctxt)(i, (char *) addr, phys_seg);
 519         }
 520 
 521         for(addr=((unsigned long) (&empty_zero_page)) + PAGE_SIZE; 
 522             addr < ((unsigned long) (&etext)); addr += PAGE_SIZE)
 523                 put_pte(addr, (get_pte(addr) & (~(PTE_W | PTE_NC))));
 524 
 525         /* Finally map the prom's address space.  Any segments that
 526          * are not the invalid segment are marked as PSEG_RESV so
 527          * they are never re-allocated.  This guarentees the PROM
 528          * a sane state if we have to return execution over to it.
 529          * Our kernel static tables make it look like nothing is
 530          * mapped in these segments, if we get a page fault for
 531          * a prom address either the user is gonna die or the kernel
 532          * is doing something *really* bad.
 533          */
 534         if(prom_begin & (~SUN4C_REAL_PGDIR_MASK)) {
 535                 panic("paging_init() Boot PROM not segmap aligned, halting...");
 536                 halt();
 537         }
 538 
 539         min_prom_segmap = 254;
 540         for(addr=KADB_DEBUGGER_BEGVM; addr < prom_end; addr += SUN4C_REAL_PGDIR_SIZE) {
 541                 if(get_segmap(addr) == invalid_segment)
 542                         continue;
 543                 phys_seg = get_segmap(addr);
 544                 if(phys_seg < min_prom_segmap) min_prom_segmap = phys_seg;
 545                 phys_seg_map[phys_seg] = PSEG_RSV;
 546                 /* Make the prom pages unaccessible from userland.  However, we
 547                  * don't touch debugger segmaps/ptes.
 548                  */
 549                 if((addr>=LINUX_OPPROM_BEGVM) && (addr<LINUX_OPPROM_ENDVM))
 550                         for(vaddr=addr; vaddr < (addr+SUN4C_REAL_PGDIR_SIZE); vaddr+=PAGE_SIZE)
 551                                 put_pte(vaddr, (get_pte(vaddr) | PTE_P));
 552 
 553                 /* Map this segment in every context */
 554                 for(i=0; i<num_contexts; i++)
 555                         (*romvec->pv_setctxt)(i, (char *) addr, phys_seg);
 556         }
 557 
 558         /* Finally, unmap kernel page zero. */
 559         put_pte(0x0, 0x0);
 560 
 561         /* Hard pin down the IO area segmaps */
 562         phys_seg = (min_prom_segmap - 1);
 563         for(addr = (IOBASE_VADDR + SUN4C_REAL_PGDIR_SIZE); addr < (IOBASE_VADDR + IOBASE_LEN);
 564             addr += SUN4C_REAL_PGDIR_SIZE) {
 565                 if(addr & (~SUN4C_REAL_PGDIR_MASK)) {
 566                         panic("paging_init() IO segment not aligned, halting...");
 567                 }
 568                 phys_seg_map[phys_seg] = PSEG_RSV; /* Don't touch */
 569                 put_segmap(addr, phys_seg--);
 570         }
 571         phys_seg_map[IOBASE_SUN4C_SEGMAP] = PSEG_RSV;
 572 
 573         start_mem = PAGE_ALIGN(mempool);
 574         start_mem = free_area_init(start_mem, end_mem);
 575         start_mem = PAGE_ALIGN(start_mem);
 576 
 577         /* That should be it. */
 578         invalidate();
 579 
 580         return start_mem;
 581 }
 582 
 583 /* Test the WP bit on the sun4c. */
 584 unsigned long
 585 sun4c_test_wp(unsigned long start_mem)
     /* [previous][next][first][last][top][bottom][index][help] */
 586 {
 587         unsigned long addr, segmap;
 588         unsigned long page_entry;
 589 
 590         wp_works_ok = -1;
 591         page_entry = pte_val(sun4c_mk_pte(PAGE_OFFSET, SUN4C_PAGE_READONLY));
 592         put_pte((unsigned long) 0x0, page_entry);
 593 
 594         /* Let it rip... */
 595         __asm__ __volatile__("st %%g0, [0x0]\n\t": : :"memory");
 596         put_pte((unsigned long) 0x0, 0x0);
 597         if (wp_works_ok < 0)
 598                 wp_works_ok = 0;
 599 
 600         /* Make all kernet static segmaps PSEG_KERNEL. */
 601         for(addr=PAGE_OFFSET; addr<start_mem; addr+=SUN4C_REAL_PGDIR_SIZE)
 602                 phys_seg_map[get_segmap(addr)]=PSEG_KERNEL;
 603 
 604         /* Map all the segmaps not valid on this machine as reserved. */
 605         for(segmap=invalid_segment; segmap<PSEG_ENTRIES; segmap++)
 606                 phys_seg_map[segmap]=PSEG_RSV;
 607 
 608         return start_mem;
 609 }
 610 
 611 /* Real work gets done here. */
 612 
 613 /* Load up routines and constants for sun4c mmu */
 614 void
 615 ld_mmu_sun4c(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 616 {
 617         printk("Loading sun4c MMU routines\n");
 618 
 619         /* First the constants */
 620         pmd_shift = SUN4C_PMD_SHIFT;
 621         pmd_size = SUN4C_PMD_SIZE;
 622         pmd_mask = SUN4C_PMD_MASK;
 623         pgdir_shift = SUN4C_PGDIR_SHIFT;
 624         pgdir_size = SUN4C_PGDIR_SIZE;
 625         pgdir_mask = SUN4C_PGDIR_MASK;
 626 
 627         ptrs_per_pte = SUN4C_PTRS_PER_PTE;
 628         ptrs_per_pmd = SUN4C_PTRS_PER_PMD;
 629         ptrs_per_pgd = SUN4C_PTRS_PER_PGD;
 630 
 631         page_none = SUN4C_PAGE_NONE;
 632         page_shared = SUN4C_PAGE_SHARED;
 633         page_copy = SUN4C_PAGE_COPY;
 634         page_readonly = SUN4C_PAGE_READONLY;
 635         page_kernel = SUN4C_PAGE_KERNEL;
 636         page_invalid = SUN4C_PAGE_INVALID;
 637         
 638         /* Functions */
 639         invalidate = sun4c_invalidate;
 640         set_pte = sun4c_set_pte;
 641         switch_to_context = sun4c_switch_to_context;
 642         pmd_align = sun4c_pmd_align;
 643         pgdir_align = sun4c_pgdir_align;
 644         vmalloc_start = sun4c_vmalloc_start;
 645 
 646         pte_page = sun4c_pte_page;
 647         pmd_page = sun4c_pmd_page;
 648         pgd_page = sun4c_pgd_page;
 649 
 650         sparc_update_rootmmu_dir = sun4c_update_rootmmu_dir;
 651 
 652         pte_none = sun4c_pte_none;
 653         pte_present = sun4c_pte_present;
 654         pte_inuse = sun4c_pte_inuse;
 655         pte_clear = sun4c_pte_clear;
 656         pte_reuse = sun4c_pte_reuse;
 657 
 658         pmd_none = sun4c_pmd_none;
 659         pmd_bad = sun4c_pmd_bad;
 660         pmd_present = sun4c_pmd_present;
 661         pmd_inuse = sun4c_pmd_inuse;
 662         pmd_clear = sun4c_pmd_clear;
 663         pmd_reuse = sun4c_pmd_reuse;
 664 
 665         pgd_none = sun4c_pgd_none;
 666         pgd_bad = sun4c_pgd_bad;
 667         pgd_present = sun4c_pgd_present;
 668         pgd_inuse = sun4c_pgd_inuse;
 669         pgd_clear = sun4c_pgd_clear;
 670         pgd_reuse = sun4c_pgd_reuse;
 671 
 672         mk_pte = sun4c_mk_pte;
 673         pgd_set = sun4c_pgd_set;
 674         pte_modify = sun4c_pte_modify;
 675         pgd_offset = sun4c_pgd_offset;
 676         pmd_offset = sun4c_pmd_offset;
 677         pte_offset = sun4c_pte_offset;
 678         pte_free_kernel = sun4c_pte_free_kernel;
 679         pmd_free_kernel = sun4c_pmd_free_kernel;
 680         pte_alloc_kernel = sun4c_pte_alloc_kernel;
 681         pmd_alloc_kernel = sun4c_pmd_alloc_kernel;
 682         pte_free = sun4c_pte_free;
 683         pte_alloc = sun4c_pte_alloc;
 684         pmd_free = sun4c_pmd_free;
 685         pmd_alloc = sun4c_pmd_alloc;
 686         pgd_free = sun4c_pgd_free;
 687         pgd_alloc = sun4c_pgd_alloc;
 688 
 689         pte_read = sun4c_pte_read;
 690         pte_write = sun4c_pte_write;
 691         pte_exec = sun4c_pte_exec;
 692         pte_dirty = sun4c_pte_dirty;
 693         pte_young = sun4c_pte_young;
 694         pte_cow = sun4c_pte_cow;
 695         pte_wrprotect = sun4c_pte_wrprotect;
 696         pte_rdprotect = sun4c_pte_rdprotect;
 697         pte_exprotect = sun4c_pte_exprotect;
 698         pte_mkclean = sun4c_pte_mkclean;
 699         pte_mkold = sun4c_pte_mkold;
 700         pte_uncow = sun4c_pte_uncow;
 701         pte_mkwrite = sun4c_pte_mkwrite;
 702         pte_mkread = sun4c_pte_mkread;
 703         pte_mkexec = sun4c_pte_mkexec;
 704         pte_mkdirty = sun4c_pte_mkdirty;
 705         pte_mkyoung = sun4c_pte_mkyoung;
 706         pte_mkcow = sun4c_pte_mkcow;
 707 
 708         return;
 709 }

/* [previous][next][first][last][top][bottom][index][help] */