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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
  3.  * Copyright (C) 1997, 2001 Ralf Baechle (ralf@gnu.org)
  4.  * Copyright (C) 2000, 2001 Broadcom Corporation
  5.  *
  6.  * This program is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU General Public License
  8.  * as published by the Free Software Foundation; either version 2
  9.  * of the License, or (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software
  18.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  */
  20. #include <linux/config.h>
  21. #include <asm/mmu_context.h>
  22. #include <asm/bootinfo.h>
  23. #include <asm/cpu.h>
  24. extern char except_vec0_r4000[];
  25. /* Dump the current entry* and pagemask registers */
  26. static inline void dump_cur_tlb_regs(void)
  27. {
  28. unsigned int entryhihi, entryhilo, entrylo0hi, entrylo0lo, entrylo1hi;
  29. unsigned int entrylo1lo, pagemask;
  30. __asm__ __volatile__ (
  31. ".set push             n"
  32. ".set noreorder        n"
  33. ".set mips64           n"
  34. ".set noat             n"
  35. "     tlbr             n"
  36. "     dmfc0  $1, $10   n"
  37. "     dsrl32 %0, $1, 0 n"
  38. "     sll    %1, $1, 0 n"
  39. "     dmfc0  $1, $2    n"
  40. "     dsrl32 %2, $1, 0 n"
  41. "     sll    %3, $1, 0 n"
  42. "     dmfc0  $1, $3    n"
  43. "     dsrl32 %4, $1, 0 n"
  44. "     sll    %5, $1, 0 n"
  45. "     mfc0   %6, $5    n"
  46. ".set pop              n"
  47. : "=r" (entryhihi),
  48. "=r" (entryhilo),
  49. "=r" (entrylo0hi),
  50. "=r" (entrylo0lo),
  51. "=r" (entrylo1hi),
  52. "=r" (entrylo1lo),
  53. "=r" (pagemask));
  54. printk("%08X%08X %08X%08X %08X%08X %08X",
  55.        entryhihi, entryhilo,
  56.        entrylo0hi, entrylo0lo,
  57.        entrylo1hi, entrylo1lo,
  58.        pagemask);
  59. }
  60. void sb1_dump_tlb(void)
  61. {
  62. unsigned long old_ctx;
  63. unsigned long flags;
  64. int entry;
  65. __save_and_cli(flags);
  66. old_ctx = get_entryhi();
  67. printk("Current TLB registers state:n"
  68.        "      EntryHi       EntryLo0          EntryLo1     PageMask  Indexn"
  69.        "--------------------------------------------------------------------n");
  70. dump_cur_tlb_regs();
  71. printk(" %08Xn", read_32bit_cp0_register(CP0_INDEX));
  72. printk("nnFull TLB Dump:n"
  73.        "Idx      EntryHi       EntryLo0          EntryLo1     PageMaskn"
  74.        "--------------------------------------------------------------n");
  75. for (entry = 0; entry < mips_cpu.tlbsize; entry++) {
  76. set_index(entry);
  77. printk("n%02i ", entry);
  78. __asm__ __volatile__ (
  79. ".set push             n"
  80. ".set mips64           n"
  81. "     tlbr             n"
  82. ".set pop              n");
  83. dump_cur_tlb_regs();
  84. }
  85. printk("n");
  86. set_entryhi(old_ctx);
  87. __restore_flags(flags);
  88. }
  89. void local_flush_tlb_all(void)
  90. {
  91. unsigned long flags;
  92. unsigned long old_ctx;
  93. int entry;
  94. __save_and_cli(flags);
  95. /* Save old context and create impossible VPN2 value */
  96. old_ctx = (get_entryhi() & 0xff);
  97. set_entrylo0(0);
  98. set_entrylo1(0);
  99. for (entry = 0; entry < mips_cpu.tlbsize; entry++) {
  100. set_entryhi(KSEG0 + (PAGE_SIZE << 1) * entry);
  101. set_index(entry);
  102. tlb_write_indexed();
  103. }
  104. set_entryhi(old_ctx);
  105. __restore_flags(flags);
  106. }
  107. /*
  108.  * Use a bogus region of memory (starting at 0) to sanitize the TLB's.
  109.  * Use increments of the maximum page size (16MB), and check for duplicate
  110.  * entries before doing a given write.  Then, when we're safe from collisions
  111.  * with the firmware, go back and give all the entries invalid addresses with
  112.  * the normal flush routine.
  113.  */
  114. void sb1_sanitize_tlb(void)
  115. {
  116. int entry;
  117. long addr = 0;
  118. long inc = 1<<24;  /* 16MB */
  119. /* Save old context and create impossible VPN2 value */
  120. set_entrylo0(0);
  121. set_entrylo1(0);
  122. for (entry = 0; entry < mips_cpu.tlbsize; entry++) {
  123. do {
  124. addr += inc;
  125. set_entryhi(addr);
  126. tlb_probe();
  127. } while ((int)(get_index()) >= 0);
  128. set_index(entry);
  129. tlb_write_indexed();
  130. }
  131. /* Now that we know we're safe from collisions, we can safely flush
  132.    the TLB with the "normal" routine. */
  133. local_flush_tlb_all();
  134. }
  135. void local_flush_tlb_range(struct mm_struct *mm, unsigned long start,
  136.                       unsigned long end)
  137. {
  138. unsigned long flags;
  139. int cpu;
  140. __save_and_cli(flags);
  141. cpu = smp_processor_id();
  142. if(CPU_CONTEXT(cpu, mm) != 0) {
  143. int size;
  144. size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
  145. size = (size + 1) >> 1;
  146. if(size <= (mips_cpu.tlbsize/2)) {
  147. int oldpid = (get_entryhi() & 0xff);
  148. int newpid = (CPU_CONTEXT(cpu, mm) & 0xff);
  149. start &= (PAGE_MASK << 1);
  150. end += ((PAGE_SIZE << 1) - 1);
  151. end &= (PAGE_MASK << 1);
  152. while(start < end) {
  153. int idx;
  154. set_entryhi(start | newpid);
  155. start += (PAGE_SIZE << 1);
  156. tlb_probe();
  157. idx = get_index();
  158. set_entrylo0(0);
  159. set_entrylo1(0);
  160. set_entryhi(KSEG0 + (idx << (PAGE_SHIFT+1)));
  161. if(idx < 0)
  162. continue;
  163. tlb_write_indexed();
  164. }
  165. set_entryhi(oldpid);
  166. } else {
  167. get_new_mmu_context(mm, cpu);
  168. if (mm == current->active_mm)
  169. set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
  170. }
  171. }
  172. __restore_flags(flags);
  173. }
  174. void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
  175. {
  176. unsigned long flags;
  177. #ifdef CONFIG_SMP
  178. /*
  179.  * This variable is eliminated from CPU_CONTEXT() if SMP isn't defined,
  180.  * so conditional it to get rid of silly "unused variable" compiler
  181.  * complaints
  182.  */
  183. int cpu = smp_processor_id();
  184. #endif
  185. __save_and_cli(flags);
  186. if (CPU_CONTEXT(cpu, vma->vm_mm) != 0) {
  187. int oldpid, newpid, idx;
  188. #ifdef DEBUG_TLB
  189. printk("[tlbpage<%d,%08lx>]", CPU_CONTEXT(cpu, vma->vm_mm), page);
  190. #endif
  191. newpid = (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff);
  192. page &= (PAGE_MASK << 1);
  193. oldpid = (get_entryhi() & 0xff);
  194. set_entryhi (page | newpid);
  195. tlb_probe();
  196. idx = get_index();
  197. set_entrylo0(0);
  198. set_entrylo1(0);
  199. if(idx < 0)
  200. goto finish;
  201. /* Make sure all entries differ. */
  202. set_entryhi(KSEG0+(idx<<(PAGE_SHIFT+1)));
  203. tlb_write_indexed();
  204. finish:
  205. set_entryhi(oldpid);
  206. }
  207. __restore_flags(flags);
  208. }
  209. /* All entries common to a mm share an asid.  To effectively flush
  210.    these entries, we just bump the asid. */
  211. void local_flush_tlb_mm(struct mm_struct *mm)
  212. {
  213. unsigned long flags;
  214. int cpu;
  215. __save_and_cli(flags);
  216. cpu = smp_processor_id();
  217. if (CPU_CONTEXT(cpu, mm) != 0) {
  218. get_new_mmu_context(mm, smp_processor_id());
  219. if (mm == current->active_mm) {
  220. set_entryhi(CPU_CONTEXT(cpu, mm) & 0xff);
  221. }
  222. }
  223. __restore_flags(flags);
  224. }
  225. /* Stolen from mips32 routines */
  226. void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
  227.                       pte_t pte)
  228. {
  229. unsigned long flags;
  230. pgd_t *pgdp;
  231. pmd_t *pmdp;
  232. pte_t *ptep;
  233. int idx, pid;
  234. /*
  235.  * Handle debugger faulting in for debugee.
  236.  */
  237. if (current->active_mm != vma->vm_mm)
  238. return;
  239. __save_and_cli(flags);
  240. pid = get_entryhi() & 0xff;
  241. #ifdef DEBUG_TLB
  242. if((pid != (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff)) || (CPU_CONTEXT(cpu, vma->vm_mm) == 0)) {
  243. printk("update_mmu_cache: Wheee, bogus tlbpid mmpid=%d tlbpid=%dn",
  244.        (int) (CPU_CONTEXT(cpu, vma->vm_mm) & 0xff), pid);
  245. }
  246. #endif
  247. address &= (PAGE_MASK << 1);
  248. set_entryhi(address | (pid));
  249. pgdp = pgd_offset(vma->vm_mm, address);
  250. tlb_probe();
  251. pmdp = pmd_offset(pgdp, address);
  252. idx = get_index();
  253. ptep = pte_offset(pmdp, address);
  254. set_entrylo0(pte_val(*ptep++) >> 6);
  255. set_entrylo1(pte_val(*ptep) >> 6);
  256. set_entryhi(address | (pid));
  257. if(idx < 0) {
  258. tlb_write_random();
  259. } else {
  260. tlb_write_indexed();
  261. }
  262. set_entryhi(pid);
  263. __restore_flags(flags);
  264. }
  265. /*
  266.  * This is called from loadmmu.c.  We have to set up all the
  267.  * memory management function pointers, as well as initialize
  268.  * the caches and tlbs
  269.  */
  270. void sb1_tlb_init(void)
  271. {
  272. u32 config1;
  273. config1 = read_mips32_cp0_config1();
  274. mips_cpu.tlbsize = ((config1 >> 25) & 0x3f) + 1;
  275. /*
  276.  * We don't know what state the firmware left the TLB's in, so this is
  277.  * the ultra-conservative way to flush the TLB's and avoid machine
  278.  * check exceptions due to duplicate TLB entries
  279.  */
  280. sb1_sanitize_tlb();
  281. memcpy((void *)KSEG0, except_vec0_r4000, 0x80);
  282. flush_icache_range(KSEG0, KSEG0 + 0x80);
  283. }