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

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * BK Id: %F% %I% %G% %U% %#%
  3.  */
  4. /*
  5.  * This file contains the routines for TLB flushing.
  6.  * On machines where the MMU uses a hash table to store virtual to
  7.  * physical translations, these routines flush entries from the the
  8.  * hash table also.
  9.  *  -- paulus
  10.  * 
  11.  *  Derived from arch/ppc/mm/init.c:
  12.  *    Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
  13.  *
  14.  *  Modifications by Paul Mackerras (PowerMac) (paulus@cs.anu.edu.au)
  15.  *  and Cort Dougan (PReP) (cort@cs.nmt.edu)
  16.  *    Copyright (C) 1996 Paul Mackerras
  17.  *  Amiga/APUS changes by Jesper Skov (jskov@cygnus.co.uk).
  18.  *
  19.  *  Derived from "arch/i386/mm/init.c"
  20.  *    Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
  21.  *
  22.  *  This program is free software; you can redistribute it and/or
  23.  *  modify it under the terms of the GNU General Public License
  24.  *  as published by the Free Software Foundation; either version
  25.  *  2 of the License, or (at your option) any later version.
  26.  *
  27.  */
  28. #include <linux/config.h>
  29. #include <linux/kernel.h>
  30. #include <linux/mm.h>
  31. #include <linux/init.h>
  32. #include "mmu_decl.h"
  33. /*
  34.  * TLB flushing:
  35.  *
  36.  *  - flush_tlb_all() flushes all processes TLBs
  37.  *  - flush_tlb_mm(mm) flushes the specified mm context TLB's
  38.  *  - flush_tlb_page(vma, vmaddr) flushes one page
  39.  *  - flush_tlb_range(mm, start, end) flushes a range of pages
  40.  *
  41.  * since the hardware hash table functions as an extension of the
  42.  * tlb as far as the linux tables are concerned, flush it too.
  43.  *    -- Cort
  44.  */
  45. /*
  46.  * Flush all tlb/hash table entries (except perhaps for those
  47.  * mapping RAM starting at PAGE_OFFSET, since they never change).
  48.  */
  49. void
  50. local_flush_tlb_all(void)
  51. {
  52. /* aargh!!! */
  53. /*
  54.  * Just flush the kernel part of the address space, that's
  55.  * all that the current callers of this require.
  56.  * Eventually I hope to persuade the powers that be that
  57.  * we can and should dispense with flush_tlb_all().
  58.  *  -- paulus.
  59.  */
  60. local_flush_tlb_range(&init_mm, TASK_SIZE, ~0UL);
  61. #ifdef CONFIG_SMP
  62. smp_send_tlb_invalidate(0);
  63. #endif /* CONFIG_SMP */
  64. }
  65. /*
  66.  * Flush all the (user) entries for the address space described
  67.  * by mm.  We can't rely on mm->mmap describing all the entries
  68.  * that might be in the hash table.
  69.  */
  70. void
  71. local_flush_tlb_mm(struct mm_struct *mm)
  72. {
  73. if (Hash == 0) {
  74. _tlbia();
  75. return;
  76. }
  77. if (mm->map_count) {
  78. struct vm_area_struct *mp;
  79. for (mp = mm->mmap; mp != NULL; mp = mp->vm_next)
  80. local_flush_tlb_range(mm, mp->vm_start, mp->vm_end);
  81. } else
  82. local_flush_tlb_range(mm, 0, TASK_SIZE);
  83. #ifdef CONFIG_SMP
  84. smp_send_tlb_invalidate(0);
  85. #endif
  86. }
  87. void
  88. local_flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr)
  89. {
  90. struct mm_struct *mm;
  91. pmd_t *pmd;
  92. pte_t *pte;
  93. if (Hash == 0) {
  94. _tlbie(vmaddr);
  95. return;
  96. }
  97. mm = (vmaddr < TASK_SIZE)? vma->vm_mm: &init_mm;
  98. pmd = pmd_offset(pgd_offset(mm, vmaddr), vmaddr);
  99. if (!pmd_none(*pmd)) {
  100. pte = pte_offset(pmd, vmaddr);
  101. if (pte_val(*pte) & _PAGE_HASHPTE)
  102. flush_hash_page(mm->context, vmaddr, pte);
  103. }
  104. #ifdef CONFIG_SMP
  105. smp_send_tlb_invalidate(0);
  106. #endif
  107. }
  108. /*
  109.  * For each address in the range, find the pte for the address
  110.  * and check _PAGE_HASHPTE bit; if it is set, find and destroy
  111.  * the corresponding HPTE.
  112.  */
  113. void
  114. local_flush_tlb_range(struct mm_struct *mm, unsigned long start, unsigned long end)
  115. {
  116. pmd_t *pmd;
  117. pte_t *pte;
  118. unsigned long pmd_end;
  119. unsigned int ctx = mm->context;
  120. if (Hash == 0) {
  121. _tlbia();
  122. return;
  123. }
  124. start &= PAGE_MASK;
  125. if (start >= end)
  126. return;
  127. pmd = pmd_offset(pgd_offset(mm, start), start);
  128. do {
  129. pmd_end = (start + PGDIR_SIZE) & PGDIR_MASK;
  130. if (!pmd_none(*pmd)) {
  131. if (!pmd_end || pmd_end > end)
  132. pmd_end = end;
  133. pte = pte_offset(pmd, start);
  134. do {
  135. if ((pte_val(*pte) & _PAGE_HASHPTE) != 0)
  136. flush_hash_page(ctx, start, pte);
  137. start += PAGE_SIZE;
  138. ++pte;
  139. } while (start && start < pmd_end);
  140. } else {
  141. start = pmd_end;
  142. }
  143. ++pmd;
  144. } while (start && start < end);
  145. #ifdef CONFIG_SMP
  146. smp_send_tlb_invalidate(0);
  147. #endif
  148. }