memory.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:15k
源码类别:

嵌入式Linux

开发平台:

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. /* As a special case allow `__pa(high_memory)'.  */
  219. if (voff == 0)
  220. return m68k_memory[i-1].addr + m68k_memory[i-1].size;
  221. return mm_vtop_fallback(vaddr);
  222. }
  223. #endif
  224. /* Separate function to make the common case faster (needs to save less
  225.    registers) */
  226. unsigned long mm_vtop_fallback(unsigned long vaddr)
  227. {
  228. /* not in one of the memory chunks; test for applying transparent
  229.  * translation */
  230. if (CPU_IS_030) {
  231.     unsigned long ttreg;
  232.     
  233.     asm volatile( ".chip 68030nt"
  234.   "pmove %/tt0,%0@nt"
  235.   ".chip 68k"
  236.   : : "a" (&ttreg) );
  237.     if (transp_transl_matches( ttreg, vaddr ))
  238. return (unsigned long)vaddr;
  239.     asm volatile( ".chip 68030nt"
  240.   "pmove %/tt1,%0@nt"
  241.   ".chip 68k"
  242.   : : "a" (&ttreg) );
  243.     if (transp_transl_matches( ttreg, vaddr ))
  244. return (unsigned long)vaddr;
  245. }
  246. else if (CPU_IS_040_OR_060) {
  247.     unsigned long ttreg;
  248.     
  249.     asm volatile( ".chip 68040nt"
  250.   "movec %%dtt0,%0nt"
  251.   ".chip 68k"
  252.   : "=d" (ttreg) );
  253.     if (transp_transl_matches( ttreg, vaddr ))
  254. return (unsigned long)vaddr;
  255.     asm volatile( ".chip 68040nt"
  256.   "movec %%dtt1,%0nt"
  257.   ".chip 68k"
  258.   : "=d" (ttreg) );
  259.     if (transp_transl_matches( ttreg, vaddr ))
  260. return (unsigned long)vaddr;
  261. }
  262. /* no match, too, so get the actual physical address from the MMU. */
  263. if (CPU_IS_060) {
  264.   mm_segment_t fs = get_fs();
  265.   unsigned long  paddr;
  266.   set_fs (MAKE_MM_SEG(SUPER_DATA));
  267.   /* The PLPAR instruction causes an access error if the translation
  268.    * is not possible. To catch this we use the same exception mechanism
  269.    * as for user space accesses in <asm/uaccess.h>. */
  270.   asm volatile (".chip 68060n"
  271. "1: plpar (%0)n"
  272. ".chip 68kn"
  273. "2:n"
  274. ".section .fixup,"ax"n"
  275. "   .evenn"
  276. "3: lea -1,%0n"
  277. "   jra 2bn"
  278. ".previousn"
  279. ".section __ex_table,"a"n"
  280. "   .align 4n"
  281. "   .long 1b,3bn"
  282. ".previous"
  283. : "=a" (paddr)
  284. : "0" (vaddr));
  285.   set_fs (fs);
  286.   return paddr;
  287. } else if (CPU_IS_040) {
  288.   unsigned long mmusr;
  289.   mm_segment_t fs = get_fs();
  290.   set_fs (MAKE_MM_SEG(SUPER_DATA));
  291.   asm volatile (".chip 68040nt"
  292. "ptestr (%1)nt"
  293. "movec %%mmusr, %0nt"
  294. ".chip 68k"
  295. : "=r" (mmusr)
  296. : "a" (vaddr));
  297.   set_fs (fs);
  298.   if (mmusr & MMU_T_040) {
  299.     return (unsigned long)vaddr; /* Transparent translation */
  300.   }
  301.   if (mmusr & MMU_R_040)
  302.     return (mmusr & PAGE_MASK) | ((unsigned long)vaddr & (PAGE_SIZE-1));
  303.   printk("VTOP040: bad virtual address %lx (%lx)", vaddr, mmusr);
  304.   return -1;
  305. } else {
  306.   volatile unsigned short temp;
  307.   unsigned short mmusr;
  308.   unsigned long *descaddr;
  309.   asm volatile ("ptestr #5,%2@,#7,%0nt"
  310. "pmove %/psr,%1@"
  311. : "=a&" (descaddr)
  312. : "a" (&temp), "a" (vaddr));
  313.   mmusr = temp;
  314.   if (mmusr & (MMU_I|MMU_B|MMU_L))
  315.     printk("VTOP030: bad virtual address %lx (%x)n", vaddr, mmusr);
  316.   descaddr = phys_to_virt((unsigned long)descaddr);
  317.   switch (mmusr & MMU_NUM) {
  318.   case 1:
  319.     return (*descaddr & 0xfe000000) | ((unsigned long)vaddr & 0x01ffffff);
  320.   case 2:
  321.     return (*descaddr & 0xfffc0000) | ((unsigned long)vaddr & 0x0003ffff);
  322.   case 3:
  323.     return (*descaddr & PAGE_MASK) | ((unsigned long)vaddr & (PAGE_SIZE-1));
  324.   default:
  325.     printk("VTOP: bad levels (%u) for virtual address %lxn", 
  326.    mmusr & MMU_NUM, vaddr);
  327.   }
  328. }
  329. printk("VTOP: bad virtual address %lxn", vaddr);
  330. return -1;
  331. }
  332. #ifndef CONFIG_SINGLE_MEMORY_CHUNK
  333. unsigned long mm_ptov (unsigned long paddr)
  334. {
  335. int i = 0;
  336. unsigned long poff, voff = PAGE_OFFSET;
  337. do {
  338. poff = paddr - m68k_memory[i].addr;
  339. if (poff < m68k_memory[i].size) {
  340. #ifdef DEBUGPV
  341. printk ("PTOV(%lx)=%lxn", paddr, poff + voff);
  342. #endif
  343. return poff + voff;
  344. }
  345. voff += m68k_memory[i].size;
  346. } while (++i < m68k_num_memory);
  347. #if DEBUG_INVALID_PTOV
  348. if (mm_inv_cnt > 0) {
  349. mm_inv_cnt--;
  350. printk("Invalid use of phys_to_virt(0x%lx) at 0x%p!n",
  351. paddr, __builtin_return_address(0));
  352. }
  353. #endif
  354. /*
  355.  * assume that the kernel virtual address is the same as the
  356.  * physical address.
  357.  *
  358.  * This should be reasonable in most situations:
  359.  *  1) They shouldn't be dereferencing the virtual address
  360.  *     unless they are sure that it is valid from kernel space.
  361.  *  2) The only usage I see so far is converting a page table
  362.  *     reference to some non-FASTMEM address space when freeing
  363.          *     mmaped "/dev/mem" pages.  These addresses are just passed
  364.  *     to "free_page", which ignores addresses that aren't in
  365.  *     the memory list anyway.
  366.  *
  367.  */
  368. #ifdef CONFIG_AMIGA
  369. /*
  370.  * if on an amiga and address is in first 16M, move it 
  371.  * to the ZTWO_VADDR range
  372.  */
  373. if (MACH_IS_AMIGA && paddr < 16*1024*1024)
  374. return ZTWO_VADDR(paddr);
  375. #endif
  376. return -1;
  377. }
  378. #endif
  379. /* invalidate page in both caches */
  380. #define clear040(paddr)
  381. __asm__ __volatile__ ("nopnt"
  382.       ".chip 68040nt"
  383.       "cinvp %%bc,(%0)nt"
  384.       ".chip 68k"
  385.       : : "a" (paddr))
  386. /* invalidate page in i-cache */
  387. #define cleari040(paddr)
  388. __asm__ __volatile__ ("nopnt"
  389.       ".chip 68040nt"
  390.       "cinvp %%ic,(%0)nt"
  391.       ".chip 68k"
  392.       : : "a" (paddr))
  393. /* push page in both caches */
  394. #define push040(paddr)
  395. __asm__ __volatile__ ("nopnt"
  396.       ".chip 68040nt"
  397.       "cpushp %%bc,(%0)nt"
  398.       ".chip 68k"
  399.       : : "a" (paddr))
  400. /* push and invalidate page in both caches, must disable ints
  401.  * to avoid invalidating valid data */
  402. #define pushcl040(paddr)
  403. do { unsigned long flags;               
  404.              save_flags(flags);                 
  405.      cli();                             
  406.              push040(paddr);
  407.      if (CPU_IS_060) clear040(paddr);
  408.      restore_flags(flags);              
  409. } while(0)
  410. /* push page in both caches, invalidate in i-cache */
  411. /* RZ: cpush %bc DOES invalidate %ic, regardless of DPI */
  412. #define pushcli040(paddr)
  413. do { push040(paddr);
  414. } while(0)
  415. /*
  416.  * 040: Hit every page containing an address in the range paddr..paddr+len-1.
  417.  * (Low order bits of the ea of a CINVP/CPUSHP are "don't care"s).
  418.  * Hit every page until there is a page or less to go. Hit the next page,
  419.  * and the one after that if the range hits it.
  420.  */
  421. /* ++roman: A little bit more care is required here: The CINVP instruction
  422.  * invalidates cache entries WITHOUT WRITING DIRTY DATA BACK! So the beginning
  423.  * and the end of the region must be treated differently if they are not
  424.  * exactly at the beginning or end of a page boundary. Else, maybe too much
  425.  * data becomes invalidated and thus lost forever. CPUSHP does what we need:
  426.  * it invalidates the page after pushing dirty data to memory. (Thanks to Jes
  427.  * for discovering the problem!)
  428.  */
  429. /* ... but on the '060, CPUSH doesn't invalidate (for us, since we have set
  430.  * the DPI bit in the CACR; would it cause problems with temporarily changing
  431.  * this?). So we have to push first and then additionally to invalidate.
  432.  */
  433. /*
  434.  * cache_clear() semantics: Clear any cache entries for the area in question,
  435.  * without writing back dirty entries first. This is useful if the data will
  436.  * be overwritten anyway, e.g. by DMA to memory. The range is defined by a
  437.  * _physical_ address.
  438.  */
  439. void cache_clear (unsigned long paddr, int len)
  440. {
  441.     if (CPU_IS_040_OR_060) {
  442. int tmp;
  443. /*
  444.  * We need special treatment for the first page, in case it
  445.  * is not page-aligned. Page align the addresses to work
  446.  * around bug I17 in the 68060.
  447.  */
  448. if ((tmp = -paddr & (PAGE_SIZE - 1))) {
  449.     pushcl040(paddr & PAGE_MASK);
  450.     if ((len -= tmp) <= 0)
  451. return;
  452.     paddr += tmp;
  453. }
  454. tmp = PAGE_SIZE;
  455. paddr &= PAGE_MASK;
  456. while ((len -= tmp) >= 0) {
  457.     clear040(paddr);
  458.     paddr += tmp;
  459. }
  460. if ((len += tmp))
  461.     /* a page boundary gets crossed at the end */
  462.     pushcl040(paddr);
  463.     }
  464.     else /* 68030 or 68020 */
  465. asm volatile ("movec %/cacr,%/d0nt"
  466.       "oriw %0,%/d0nt"
  467.       "movec %/d0,%/cacr"
  468.       : : "i" (FLUSH_I_AND_D)
  469.       : "d0");
  470. #ifdef CONFIG_M68K_L2_CACHE
  471.     if(mach_l2_flush)
  472.      mach_l2_flush(0);
  473. #endif
  474. }
  475. /*
  476.  * cache_push() semantics: Write back any dirty cache data in the given area,
  477.  * and invalidate the range in the instruction cache. It needs not (but may)
  478.  * invalidate those entries also in the data cache. The range is defined by a
  479.  * _physical_ address.
  480.  */
  481. void cache_push (unsigned long paddr, int len)
  482. {
  483.     if (CPU_IS_040_OR_060) {
  484. int tmp = PAGE_SIZE;
  485. /*
  486.          * on 68040 or 68060, push cache lines for pages in the range;
  487.  * on the '040 this also invalidates the pushed lines, but not on
  488.  * the '060!
  489.  */
  490. len += paddr & (PAGE_SIZE - 1);
  491. /*
  492.  * Work around bug I17 in the 68060 affecting some instruction
  493.  * lines not being invalidated properly.
  494.  */
  495. paddr &= PAGE_MASK;
  496. do {
  497.     pushcli040(paddr);
  498.     paddr += tmp;
  499. } while ((len -= tmp) > 0);
  500.     }
  501.     /*
  502.      * 68030/68020 have no writeback cache. On the other hand,
  503.      * cache_push is actually a superset of cache_clear (the lines
  504.      * get written back and invalidated), so we should make sure
  505.      * to perform the corresponding actions. After all, this is getting
  506.      * called in places where we've just loaded code, or whatever, so
  507.      * flushing the icache is appropriate; flushing the dcache shouldn't
  508.      * be required.
  509.      */
  510.     else /* 68030 or 68020 */
  511. asm volatile ("movec %/cacr,%/d0nt"
  512.       "oriw %0,%/d0nt"
  513.       "movec %/d0,%/cacr"
  514.       : : "i" (FLUSH_I)
  515.       : "d0");
  516. #ifdef CONFIG_M68K_L2_CACHE
  517.     if(mach_l2_flush)
  518.      mach_l2_flush(1);
  519. #endif
  520. }
  521. #undef clear040
  522. #undef cleari040
  523. #undef push040
  524. #undef pushcl040
  525. #undef pushcli040
  526. #ifndef CONFIG_SINGLE_MEMORY_CHUNK
  527. int mm_end_of_chunk (unsigned long addr, int len)
  528. {
  529. int i;
  530. for (i = 0; i < m68k_num_memory; i++)
  531. if (m68k_memory[i].addr + m68k_memory[i].size == addr + len)
  532. return 1;
  533. return 0;
  534. }
  535. #endif