mips_mmu.c 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. * Date Author Notes
  8. * 2020-07-26 lizhirui the first version
  9. */
  10. #include <string.h>
  11. #include <stdlib.h>
  12. #include "mips.h"
  13. #include "mips_mmu.h"
  14. void mmu_init()
  15. {
  16. uint32_t status = read_c0_status();
  17. status |= 0x07 << 5;//ux = 1,sx = 1,kx = 1
  18. write_c0_status(status);
  19. mmu_clear_tlb();
  20. mmu_clear_itlb();
  21. }
  22. void mmu_set_cpu_mode(cpu_mode_t cpu_mode)
  23. {
  24. uint32_t status = read_c0_status();
  25. status &= ~(0x03 << 3);
  26. status |= ((uint32_t)cpu_mode & 0x03) << 3;
  27. write_c0_status(status);
  28. }
  29. cpu_mode_t mmu_get_cpu_mode()
  30. {
  31. uint32_t status = read_c0_status();
  32. return (cpu_mode_t)((status >> 3) & 0x03);
  33. }
  34. void mmu_clear_tlb()
  35. {
  36. uint32_t max_tlb_index = mmu_get_max_tlb_index();
  37. uint64_t va = KSEG0BASE;
  38. uint32_t entry;
  39. tlb_item_t tlb_item;
  40. for(entry = 0;entry <= max_tlb_index;entry++)
  41. {
  42. mmu_tlb_item_init(&tlb_item);
  43. mmu_tlb_write_indexed(entry,&tlb_item);
  44. }
  45. }
  46. void mmu_clear_itlb()
  47. {
  48. uint32_t diag = read_c0_diag();
  49. write_c0_diag(diag | (0x01 << 2));//write ITLB bit
  50. read_c0_entrylo0();
  51. }
  52. uint32_t mmu_get_max_tlb_index()
  53. {
  54. uint32_t config1 = read_c0_config1();
  55. return ((config1 >> 25) & 0x3F);
  56. }
  57. void mmu_tlb_write_indexed(uint32_t index,tlb_item_t *tlb_item)
  58. {
  59. tlb_item -> entry_lo[0].g |= tlb_item -> entry_lo[1].g;
  60. tlb_item -> entry_lo[1].g |= tlb_item -> entry_lo[0].g;
  61. mmu_tlb_set_index(index);
  62. write_c0_entrylo0(reg_type_convert(tlb_item -> entry_lo[0],uint64_t));
  63. write_c0_entrylo1(reg_type_convert(tlb_item -> entry_lo[1],uint64_t));
  64. write_c0_entryhi(reg_type_convert(tlb_item -> entry_hi,uint64_t));
  65. write_c0_pagemask(reg_type_convert(tlb_item -> page_mask,uint64_t));
  66. tlb_write_indexed();
  67. read_c0_entrylo0();
  68. }
  69. void mmu_tlb_write_random(tlb_item_t *tlb_item)
  70. {
  71. tlb_item -> entry_lo[0].g |= tlb_item -> entry_lo[1].g;
  72. tlb_item -> entry_lo[1].g |= tlb_item -> entry_lo[0].g;
  73. write_c0_entrylo0(reg_type_convert(tlb_item -> entry_lo[0],uint64_t));
  74. write_c0_entrylo1(reg_type_convert(tlb_item -> entry_lo[1],uint64_t));
  75. write_c0_entryhi(reg_type_convert(tlb_item -> entry_hi,uint64_t));
  76. write_c0_pagemask(reg_type_convert(tlb_item -> page_mask,uint64_t));
  77. tlb_write_random();
  78. read_c0_entrylo0();
  79. }
  80. void mmu_tlb_read(uint32_t index,tlb_item_t *tlb_item)
  81. {
  82. mmu_tlb_set_index(index);
  83. tlb_read();
  84. uint64_t entrylo[2];
  85. uint64_t entryhi;
  86. uint64_t page_mask;
  87. entrylo[0] = read_c0_entrylo0();
  88. entrylo[1] = read_c0_entrylo1();
  89. entryhi = read_c0_entryhi();
  90. page_mask = read_c0_pagemask();
  91. tlb_item -> entry_lo[0] = reg_type_convert(entrylo[0],entry_lo_t);
  92. tlb_item -> entry_lo[1] = reg_type_convert(entrylo[1],entry_lo_t);
  93. tlb_item -> entry_hi = reg_type_convert(entryhi,entry_hi_t);
  94. tlb_item -> page_mask = reg_type_convert(page_mask,page_mask_t);
  95. }
  96. uint32_t mmu_tlb_find(uint64_t vpn,uint32_t asid,uint32_t *index)
  97. {
  98. entry_hi_t entry_hi;
  99. entry_hi.r = (vpn >> 62) & 0x03;
  100. entry_hi.vpn2 = (vpn >> 13) & 0x7FFFFFFU;
  101. entry_hi.asid = asid & 0xFFU;
  102. tlb_item_t tlb_item;
  103. //mmu_tlb_read(6,&tlb_item);
  104. //tlb_dump();
  105. mmu_tlb_item_init(&tlb_item);
  106. tlb_item.entry_lo[0].g = tlb_item.entry_lo[1].g = 1;
  107. read_c0_entrylo0();//i don't know why,but if i don't read any register of mmu,tplb will be failed in qemu.
  108. write_c0_entrylo0(reg_type_convert(tlb_item.entry_lo[0],uint64_t));
  109. write_c0_entrylo1(reg_type_convert(tlb_item.entry_lo[1],uint64_t));
  110. write_c0_entryhi(reg_type_convert(entry_hi,uint64_t));
  111. //__asm__ __volatile__("ehb");
  112. //read_c0_entryhi();
  113. //rt_kprintf("entry_hi = %p\n",read_c0_entryhi());
  114. tlb_probe();
  115. *index = mmu_tlb_get_index();
  116. return mmu_tlb_is_matched();
  117. }
  118. void mmu_tlb_item_init(tlb_item_t *tlb_item)
  119. {
  120. memset(tlb_item,0,sizeof(tlb_item_t));
  121. tlb_item -> entry_lo[0].c = 0x03;
  122. tlb_item -> entry_lo[1].c = 0x03;
  123. }
  124. void mmu_set_map(uint64_t vpn,uint64_t ppn,page_mask_enum_t page_mask,uint32_t asid,uint32_t global)
  125. {
  126. uint64_t page_mask_v = (uint64_t)page_mask;
  127. /*if(page_mask_v & (1 << 13))
  128. {
  129. page_mask_v |= (1 << 12);
  130. }*/
  131. uint64_t lb = lowbit((~(page_mask_v)) << 12);
  132. uint64_t pn_remained = ((~(page_mask_v)) << 12) | lb;
  133. vpn &= pn_remained;
  134. ppn &= pn_remained;
  135. uint64_t odd_vpn = vpn | lb;
  136. uint64_t even_vpn = vpn & (~lb);
  137. uint32_t index;
  138. tlb_item_t tlb_item,tlb2_item;
  139. mmu_tlb_item_init(&tlb_item);
  140. mmu_tlb_item_init(&tlb2_item);
  141. tlb_item.page_mask.mask = page_mask;
  142. if(mmu_tlb_find(vpn & (~lb),asid,&index))
  143. {
  144. mmu_tlb_read(index,&tlb_item);
  145. mmu_tlb_write_indexed(index,&tlb2_item);
  146. }
  147. entry_lo_t *entry_lo = &tlb_item.entry_lo[vpn == even_vpn ? 0 : 1];
  148. tlb_item.entry_lo[0].g = tlb_item.entry_lo[1].g = global;
  149. entry_lo -> d = 1;
  150. entry_lo -> ri = 0;
  151. entry_lo -> xi = 0;
  152. entry_lo -> v = 1;
  153. entry_lo -> pfn = ppn >> 12;
  154. tlb_item.entry_hi.r = (vpn >> 62) & 0x03;
  155. tlb_item.entry_hi.vpn2 = (vpn >> 13) & 0x7FFFFFFU;
  156. tlb_item.entry_hi.asid = asid & 0xFFU;
  157. mmu_tlb_write_random(&tlb_item);
  158. }
  159. uint32_t mmu_tlb_get_random()
  160. {
  161. return read_c0_random();
  162. }
  163. uint32_t mmu_tlb_get_index()
  164. {
  165. return read_c0_index() & 0x3F;
  166. }
  167. void mmu_tlb_set_index(uint32_t index)
  168. {
  169. write_c0_index(index & 0x3F);
  170. }
  171. uint32_t mmu_tlb_is_matched()
  172. {
  173. return (read_c0_index() & 0x80000000) == 0;
  174. }
  175. uint64_t mmu_tlb_get_bad_vaddr()
  176. {
  177. return read_c0_badvaddr();
  178. }
  179. void tlb_dump()
  180. {
  181. uint32_t max_index = mmu_get_max_tlb_index();
  182. //uint32_t max_index = 10;
  183. uint32_t entry;
  184. tlb_item_t tlb_item;
  185. for(entry = 0;entry <= max_index;entry++)
  186. {
  187. mmu_tlb_read(entry,&tlb_item);
  188. //mmu_tlb_write_indexed(entry,&tlb_item);
  189. //mmu_tlb_read(entry,&tlb_item);
  190. rt_kprintf("vpn = 0x%p,ppn0 = 0x%p,ppn1 = 0x%p\n",(uint64_t)tlb_item.entry_hi.vpn2 << 13 | (uint64_t)tlb_item.entry_hi.asid << 62,(uint64_t)tlb_item.entry_lo[0].pfn << 12,(uint64_t)tlb_item.entry_lo[1].pfn << 12);
  191. rt_kprintf("v = %d,d = %d,g = %d,ri = %d,xi = %d,c = %d\n",tlb_item.entry_lo[0].v,tlb_item.entry_lo[0].d,tlb_item.entry_lo[0].g,tlb_item.entry_lo[0].ri,tlb_item.entry_lo[0].xi,tlb_item.entry_lo[0].c);
  192. rt_kprintf("v = %d,d = %d,g = %d,ri = %d,xi = %d,c = %d\n",tlb_item.entry_lo[1].v,tlb_item.entry_lo[1].d,tlb_item.entry_lo[1].g,tlb_item.entry_lo[1].ri,tlb_item.entry_lo[1].xi,tlb_item.entry_lo[1].c);
  193. }
  194. }