memory.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:15k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  linux/arch/m68k/mm/memory.c
  3.  *
  4.  *  Copyright (C) 1995  Hamish Macdonald
  5.  */
  6. #include <linux/config.h>
  7. #include <linux/mm.h>
  8. #include <linux/kernel.h>
  9. #include <linux/string.h>
  10. #include <linux/types.h>
  11. #include <linux/slab.h>
  12. #include <linux/init.h>
  13. #include <linux/pagemap.h>
  14. #include <asm/setup.h>
  15. #include <asm/segment.h>
  16. #include <asm/page.h>
  17. #include <asm/pgalloc.h>
  18. #include <asm/system.h>
  19. #include <asm/traps.h>
  20. #include <asm/io.h>
  21. #include <asm/machdep.h>
  22. #ifdef CONFIG_AMIGA
  23. #include <asm/amigahw.h>
  24. #endif
  25. struct pgtable_cache_struct quicklists;
  26. void __bad_pte(pmd_t *pmd)
  27. {
  28. printk("Bad pmd in pte_alloc: %08lxn", pmd_val(*pmd));
  29. pmd_set(pmd, BAD_PAGETABLE);
  30. }
  31. void __bad_pmd(pgd_t *pgd)
  32. {
  33. printk("Bad pgd in pmd_alloc: %08lxn", pgd_val(*pgd));
  34. pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
  35. }
  36. #if 0
  37. pte_t *get_pte_slow(pmd_t *pmd, unsigned long offset)
  38. {
  39. pte_t *pte;
  40. pte = (pte_t *) __get_free_page(GFP_KERNEL);
  41. if (pmd_none(*pmd)) {
  42. if (pte) {
  43. clear_page(pte);
  44. __flush_page_to_ram((unsigned long)pte);
  45. flush_tlb_kernel_page((unsigned long)pte);
  46. nocache_page((unsigned long)pte);
  47. pmd_set(pmd, pte);
  48. return pte + offset;
  49. }
  50. pmd_set(pmd, BAD_PAGETABLE);
  51. return NULL;
  52. }
  53. free_page((unsigned long)pte);
  54. if (pmd_bad(*pmd)) {
  55. __bad_pte(pmd);
  56. return NULL;
  57. }
  58. return (pte_t *)__pmd_page(*pmd) + offset;
  59. }
  60. #endif
  61. #if 0
  62. pmd_t *get_pmd_slow(pgd_t *pgd, unsigned long offset)
  63. {
  64. pmd_t *pmd;
  65. pmd = get_pointer_table();
  66. if (pgd_none(*pgd)) {
  67. if (pmd) {
  68. pgd_set(pgd, pmd);
  69. return pmd + offset;
  70. }
  71. pgd_set(pgd, (pmd_t *)BAD_PAGETABLE);
  72. return NULL;
  73. }
  74. free_pointer_table(pmd);
  75. if (pgd_bad(*pgd)) {
  76. __bad_pmd(pgd);
  77. return NULL;
  78. }
  79. return (pmd_t *)__pgd_page(*pgd) + offset;
  80. }
  81. #endif
  82. /* ++andreas: {get,free}_pointer_table rewritten to use unused fields from
  83.    struct page instead of separately kmalloced struct.  Stolen from
  84.    arch/sparc/mm/srmmu.c ... */
  85. typedef struct list_head ptable_desc;
  86. static LIST_HEAD(ptable_list);
  87. #define PD_PTABLE(page) ((ptable_desc *)virt_to_page(page))
  88. #define PD_PAGE(ptable) (list_entry(ptable, struct page, list))
  89. #define PD_MARKBITS(dp) (*(unsigned char *)&PD_PAGE(dp)->index)
  90. #define PTABLE_SIZE (PTRS_PER_PMD * sizeof(pmd_t))
  91. void __init init_pointer_table(unsigned long ptable)
  92. {
  93. ptable_desc *dp;
  94. unsigned long page = ptable & PAGE_MASK;
  95. unsigned char mask = 1 << ((ptable - page)/PTABLE_SIZE);
  96. dp = PD_PTABLE(page);
  97. if (!(PD_MARKBITS(dp) & mask)) {
  98. PD_MARKBITS(dp) = 0xff;
  99. list_add(dp, &ptable_list);
  100. }
  101. PD_MARKBITS(dp) &= ~mask;
  102. #ifdef DEBUG
  103. printk("init_pointer_table: %lx, %xn", ptable, PD_MARKBITS(dp));
  104. #endif
  105. /* unreserve the page so it's possible to free that page */
  106. PD_PAGE(dp)->flags &= ~(1 << PG_reserved);
  107. atomic_set(&PD_PAGE(dp)->count, 1);
  108. return;
  109. }
  110. pmd_t *get_pointer_table (void)
  111. {
  112. ptable_desc *dp = ptable_list.next;
  113. unsigned char mask = PD_MARKBITS (dp);
  114. unsigned char tmp;
  115. unsigned int off;
  116. /*
  117.  * For a pointer table for a user process address space, a
  118.  * table is taken from a page allocated for the purpose.  Each
  119.  * page can hold 8 pointer tables.  The page is remapped in
  120.  * virtual address space to be noncacheable.
  121.  */
  122. if (mask == 0) {
  123. unsigned long page;
  124. ptable_desc *new;
  125. if (!(page = get_free_page (GFP_KERNEL)))
  126. return 0;
  127. flush_tlb_kernel_page(page);
  128. nocache_page (page);
  129. new = PD_PTABLE(page);
  130. PD_MARKBITS(new) = 0xfe;
  131. list_add_tail(new, dp);
  132. return (pmd_t *)page;
  133. }
  134. for (tmp = 1, off = 0; (mask & tmp) == 0; tmp <<= 1, off += PTABLE_SIZE)
  135. ;
  136. PD_MARKBITS(dp) = mask & ~tmp;
  137. if (!PD_MARKBITS(dp)) {
  138. /* move to end of list */
  139. list_del(dp);
  140. list_add_tail(dp, &ptable_list);
  141. }
  142. return (pmd_t *) (page_address(PD_PAGE(dp)) + off);
  143. }
  144. int free_pointer_table (pmd_t *ptable)
  145. {
  146. ptable_desc *dp;
  147. unsigned long page = (unsigned long)ptable & PAGE_MASK;
  148. unsigned char mask = 1 << (((unsigned long)ptable - page)/PTABLE_SIZE);
  149. dp = PD_PTABLE(page);
  150. if (PD_MARKBITS (dp) & mask)
  151. panic ("table already free!");
  152. PD_MARKBITS (dp) |= mask;
  153. if (PD_MARKBITS(dp) == 0xff) {
  154. /* all tables in page are free, free page */
  155. list_del(dp);
  156. cache_page (page);
  157. free_page (page);
  158. return 1;
  159. } else if (ptable_list.next != dp) {
  160. /*
  161.  * move this descriptor to the front of the list, since
  162.  * it has one or more free tables.
  163.  */
  164. list_del(dp);
  165. list_add(dp, &ptable_list);
  166. }
  167. return 0;
  168. }
  169. static unsigned long transp_transl_matches( unsigned long regval,
  170.     unsigned long vaddr )
  171. {
  172.     unsigned long base, mask;
  173.     /* enabled? */
  174.     if (!(regval & 0x8000))
  175. return( 0 );
  176.     if (CPU_IS_030) {
  177. /* function code match? */
  178. base = (regval >> 4) & 7;
  179. mask = ~(regval & 7);
  180. if (((SUPER_DATA ^ base) & mask) != 0)
  181.     return 0;
  182.     }
  183.     else {
  184. /* must not be user-only */
  185. if ((regval & 0x6000) == 0)
  186.     return( 0 );
  187.     }
  188.     /* address match? */
  189.     base = regval & 0xff000000;
  190.     mask = ~(regval << 8) & 0xff000000;
  191.     return (((unsigned long)vaddr ^ base) & mask) == 0;
  192. }
  193. #if DEBUG_INVALID_PTOV
  194. int mm_inv_cnt = 5;
  195. #endif
  196. #ifndef CONFIG_SINGLE_MEMORY_CHUNK
  197. /*
  198.  * The following two routines map from a physical address to a kernel
  199.  * virtual address and vice versa.
  200.  */
  201. unsigned long mm_vtop(unsigned long vaddr)
  202. {
  203. int i=0;
  204. unsigned long voff = (unsigned long)vaddr - PAGE_OFFSET;
  205. do {
  206. if (voff < m68k_memory[i].size) {
  207. #ifdef DEBUGPV
  208. printk ("VTOP(%p)=%lxn", vaddr,
  209. m68k_memory[i].addr + voff);
  210. #endif
  211. return m68k_memory[i].addr + voff;
  212. }
  213. voff -= m68k_memory[i].size;
  214. } while (++i < m68k_num_memory);
  215. /* As a special case allow `__pa(high_memory)'.  */
  216. if (voff == 0)
  217. return m68k_memory[i-1].addr + m68k_memory[i-1].size;
  218. return mm_vtop_fallback(vaddr);
  219. }
  220. #endif
  221. /* Separate function to make the common case faster (needs to save less
  222.    registers) */
  223. unsigned long mm_vtop_fallback(unsigned long vaddr)
  224. {
  225. /* not in one of the memory chunks; test for applying transparent
  226.  * translation */
  227. if (CPU_IS_030) {
  228.     unsigned long ttreg;
  229.     
  230.     asm volatile( ".chip 68030nt"
  231.   "pmove %/tt0,%0@nt"
  232.   ".chip 68k"
  233.   : : "a" (&ttreg) );
  234.     if (transp_transl_matches( ttreg, vaddr ))
  235. return (unsigned long)vaddr;
  236.     asm volatile( ".chip 68030nt"
  237.   "pmove %/tt1,%0@nt"
  238.   ".chip 68k"
  239.   : : "a" (&ttreg) );
  240.     if (transp_transl_matches( ttreg, vaddr ))
  241. return (unsigned long)vaddr;
  242. }
  243. else if (CPU_IS_040_OR_060) {
  244.     unsigned long ttreg;
  245.     
  246.     asm volatile( ".chip 68040nt"
  247.   "movec %%dtt0,%0nt"
  248.   ".chip 68k"
  249.   : "=d" (ttreg) );
  250.     if (transp_transl_matches( ttreg, vaddr ))
  251. return (unsigned long)vaddr;
  252.     asm volatile( ".chip 68040nt"
  253.   "movec %%dtt1,%0nt"
  254.   ".chip 68k"
  255.   : "=d" (ttreg) );
  256.     if (transp_transl_matches( ttreg, vaddr ))
  257. return (unsigned long)vaddr;
  258. }
  259. /* no match, too, so get the actual physical address from the MMU. */
  260. if (CPU_IS_060) {
  261.   mm_segment_t fs = get_fs();
  262.   unsigned long  paddr;
  263.   set_fs (MAKE_MM_SEG(SUPER_DATA));
  264.   /* The PLPAR instruction causes an access error if the translation
  265.    * is not possible. To catch this we use the same exception mechanism
  266.    * as for user space accesses in <asm/uaccess.h>. */
  267.   asm volatile (".chip 68060n"
  268. "1: plpar (%0)n"
  269. ".chip 68kn"
  270. "2:n"
  271. ".section .fixup,"ax"n"
  272. "   .evenn"
  273. "3: lea -1,%0n"
  274. "   jra 2bn"
  275. ".previousn"
  276. ".section __ex_table,"a"n"
  277. "   .align 4n"
  278. "   .long 1b,3bn"
  279. ".previous"
  280. : "=a" (paddr)
  281. : "0" (vaddr));
  282.   set_fs (fs);
  283.   return paddr;
  284. } else if (CPU_IS_040) {
  285.   unsigned long mmusr;
  286.   mm_segment_t fs = get_fs();
  287.   set_fs (MAKE_MM_SEG(SUPER_DATA));
  288.   asm volatile (".chip 68040nt"
  289. "ptestr (%1)nt"
  290. "movec %%mmusr, %0nt"
  291. ".chip 68k"
  292. : "=r" (mmusr)
  293. : "a" (vaddr));
  294.   set_fs (fs);
  295.   if (mmusr & MMU_T_040) {
  296.     return (unsigned long)vaddr; /* Transparent translation */
  297.   }
  298.   if (mmusr & MMU_R_040)
  299.     return (mmusr & PAGE_MASK) | ((unsigned long)vaddr & (PAGE_SIZE-1));
  300.   printk("VTOP040: bad virtual address %lx (%lx)", vaddr, mmusr);
  301.   return -1;
  302. } else {
  303.   volatile unsigned short temp;
  304.   unsigned short mmusr;
  305.   unsigned long *descaddr;
  306.   asm volatile ("ptestr #5,%2@,#7,%0nt"
  307. "pmove %/psr,%1@"
  308. : "=a&" (descaddr)
  309. : "a" (&temp), "a" (vaddr));
  310.   mmusr = temp;
  311.   if (mmusr & (MMU_I|MMU_B|MMU_L))
  312.     printk("VTOP030: bad virtual address %lx (%x)n", vaddr, mmusr);
  313.   descaddr = phys_to_virt((unsigned long)descaddr);
  314.   switch (mmusr & MMU_NUM) {
  315.   case 1:
  316.     return (*descaddr & 0xfe000000) | ((unsigned long)vaddr & 0x01ffffff);
  317.   case 2:
  318.     return (*descaddr & 0xfffc0000) | ((unsigned long)vaddr & 0x0003ffff);
  319.   case 3:
  320.     return (*descaddr & PAGE_MASK) | ((unsigned long)vaddr & (PAGE_SIZE-1));
  321.   default:
  322.     printk("VTOP: bad levels (%u) for virtual address %lxn", 
  323.    mmusr & MMU_NUM, vaddr);
  324.   }
  325. }
  326. printk("VTOP: bad virtual address %lxn", vaddr);
  327. return -1;
  328. }
  329. #ifndef CONFIG_SINGLE_MEMORY_CHUNK
  330. unsigned long mm_ptov (unsigned long paddr)
  331. {
  332. int i = 0;
  333. unsigned long poff, voff = PAGE_OFFSET;
  334. do {
  335. poff = paddr - m68k_memory[i].addr;
  336. if (poff < m68k_memory[i].size) {
  337. #ifdef DEBUGPV
  338. printk ("PTOV(%lx)=%lxn", paddr, poff + voff);
  339. #endif
  340. return poff + voff;
  341. }
  342. voff += m68k_memory[i].size;
  343. } while (++i < m68k_num_memory);
  344. #if DEBUG_INVALID_PTOV
  345. if (mm_inv_cnt > 0) {
  346. mm_inv_cnt--;
  347. printk("Invalid use of phys_to_virt(0x%lx) at 0x%p!n",
  348. paddr, __builtin_return_address(0));
  349. }
  350. #endif
  351. /*
  352.  * assume that the kernel virtual address is the same as the
  353.  * physical address.
  354.  *
  355.  * This should be reasonable in most situations:
  356.  *  1) They shouldn't be dereferencing the virtual address
  357.  *     unless they are sure that it is valid from kernel space.
  358.  *  2) The only usage I see so far is converting a page table
  359.  *     reference to some non-FASTMEM address space when freeing
  360.          *     mmaped "/dev/mem" pages.  These addresses are just passed
  361.  *     to "free_page", which ignores addresses that aren't in
  362.  *     the memory list anyway.
  363.  *
  364.  */
  365. #ifdef CONFIG_AMIGA
  366. /*
  367.  * if on an amiga and address is in first 16M, move it 
  368.  * to the ZTWO_VADDR range
  369.  */
  370. if (MACH_IS_AMIGA && paddr < 16*1024*1024)
  371. return ZTWO_VADDR(paddr);
  372. #endif
  373. return -1;
  374. }
  375. #endif
  376. /* invalidate page in both caches */
  377. #define clear040(paddr)
  378. __asm__ __volatile__ ("nopnt"
  379.       ".chip 68040nt"
  380.       "cinvp %%bc,(%0)nt"
  381.       ".chip 68k"
  382.       : : "a" (paddr))
  383. /* invalidate page in i-cache */
  384. #define cleari040(paddr)
  385. __asm__ __volatile__ ("nopnt"
  386.       ".chip 68040nt"
  387.       "cinvp %%ic,(%0)nt"
  388.       ".chip 68k"
  389.       : : "a" (paddr))
  390. /* push page in both caches */
  391. #define push040(paddr)
  392. __asm__ __volatile__ ("nopnt"
  393.       ".chip 68040nt"
  394.       "cpushp %%bc,(%0)nt"
  395.       ".chip 68k"
  396.       : : "a" (paddr))
  397. /* push and invalidate page in both caches, must disable ints
  398.  * to avoid invalidating valid data */
  399. #define pushcl040(paddr)
  400. do { unsigned long flags;               
  401.              save_flags(flags);                 
  402.      cli();                             
  403.              push040(paddr);
  404.      if (CPU_IS_060) clear040(paddr);
  405.      restore_flags(flags);              
  406. } while(0)
  407. /* push page in both caches, invalidate in i-cache */
  408. /* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */
  409. #define pushcli040(paddr)
  410. do { push040(paddr);
  411. } while(0)
  412. /*
  413.  * 040: Hit every page containing an address in the range paddr..paddr+len-1.
  414.  * (Low order bits of the ea of a CINVP/CPUSHP are "don't care"s).
  415.  * Hit every page until there is a page or less to go. Hit the next page,
  416.  * and the one after that if the range hits it.
  417.  */
  418. /* ++roman: A little bit more care is required here: The CINVP instruction
  419.  * invalidates cache entries WITHOUT WRITING DIRTY DATA BACK! So the beginning
  420.  * and the end of the region must be treated differently if they are not
  421.  * exactly at the beginning or end of a page boundary. Else, maybe too much
  422.  * data becomes invalidated and thus lost forever. CPUSHP does what we need:
  423.  * it invalidates the page after pushing dirty data to memory. (Thanks to Jes
  424.  * for discovering the problem!)
  425.  */
  426. /* ... but on the '060, CPUSH doesn't invalidate (for us, since we have set
  427.  * the DPI bit in the CACR; would it cause problems with temporarily changing
  428.  * this?). So we have to push first and then additionally to invalidate.
  429.  */
  430. /*
  431.  * cache_clear() semantics: Clear any cache entries for the area in question,
  432.  * without writing back dirty entries first. This is useful if the data will
  433.  * be overwritten anyway, e.g. by DMA to memory. The range is defined by a
  434.  * _physical_ address.
  435.  */
  436. void cache_clear (unsigned long paddr, int len)
  437. {
  438.     if (CPU_IS_040_OR_060) {
  439. int tmp;
  440. /*
  441.  * We need special treatment for the first page, in case it
  442.  * is not page-aligned. Page align the addresses to work
  443.  * around bug I17 in the 68060.
  444.  */
  445. if ((tmp = -paddr & (PAGE_SIZE - 1))) {
  446.     pushcl040(paddr & PAGE_MASK);
  447.     if ((len -= tmp) <= 0)
  448. return;
  449.     paddr += tmp;
  450. }
  451. tmp = PAGE_SIZE;
  452. paddr &= PAGE_MASK;
  453. while ((len -= tmp) >= 0) {
  454.     clear040(paddr);
  455.     paddr += tmp;
  456. }
  457. if ((len += tmp))
  458.     /* a page boundary gets crossed at the end */
  459.     pushcl040(paddr);
  460.     }
  461.     else /* 68030 or 68020 */
  462. asm volatile ("movec %/cacr,%/d0nt"
  463.       "oriw %0,%/d0nt"
  464.       "movec %/d0,%/cacr"
  465.       : : "i" (FLUSH_I_AND_D)
  466.       : "d0");
  467. #ifdef CONFIG_M68K_L2_CACHE
  468.     if(mach_l2_flush)
  469.      mach_l2_flush(0);
  470. #endif
  471. }
  472. /*
  473.  * cache_push() semantics: Write back any dirty cache data in the given area,
  474.  * and invalidate the range in the instruction cache. It needs not (but may)
  475.  * invalidate those entries also in the data cache. The range is defined by a
  476.  * _physical_ address.
  477.  */
  478. void cache_push (unsigned long paddr, int len)
  479. {
  480.     if (CPU_IS_040_OR_060) {
  481. int tmp = PAGE_SIZE;
  482. /*
  483.          * on 68040 or 68060, push cache lines for pages in the range;
  484.  * on the '040 this also invalidates the pushed lines, but not on
  485.  * the '060!
  486.  */
  487. len += paddr & (PAGE_SIZE - 1);
  488. /*
  489.  * Work around bug I17 in the 68060 affecting some instruction
  490.  * lines not being invalidated properly.
  491.  */
  492. paddr &= PAGE_MASK;
  493. do {
  494.     pushcli040(paddr);
  495.     paddr += tmp;
  496. } while ((len -= tmp) > 0);
  497.     }
  498.     /*
  499.      * 68030/68020 have no writeback cache. On the other hand,
  500.      * cache_push is actually a superset of cache_clear (the lines
  501.      * get written back and invalidated), so we should make sure
  502.      * to perform the corresponding actions. After all, this is getting
  503.      * called in places where we've just loaded code, or whatever, so
  504.      * flushing the icache is appropriate; flushing the dcache shouldn't
  505.      * be required.
  506.      */
  507.     else /* 68030 or 68020 */
  508. asm volatile ("movec %/cacr,%/d0nt"
  509.       "oriw %0,%/d0nt"
  510.       "movec %/d0,%/cacr"
  511.       : : "i" (FLUSH_I)
  512.       : "d0");
  513. #ifdef CONFIG_M68K_L2_CACHE
  514.     if(mach_l2_flush)
  515.      mach_l2_flush(1);
  516. #endif
  517. }
  518. #undef clear040
  519. #undef cleari040
  520. #undef push040
  521. #undef pushcl040
  522. #undef pushcli040
  523. #ifndef CONFIG_SINGLE_MEMORY_CHUNK
  524. int mm_end_of_chunk (unsigned long addr, int len)
  525. {
  526. int i;
  527. for (i = 0; i < m68k_num_memory; i++)
  528. if (m68k_memory[i].addr + m68k_memory[i].size == addr + len)
  529. return 1;
  530. return 0;
  531. }
  532. #endif