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