/[gxemul]/trunk/src/cpus/memory_mips_v2p.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/src/cpus/memory_mips_v2p.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 26 - (show annotations)
Mon Oct 8 16:20:10 2007 UTC (13 years, 3 months ago) by dpavlin
File MIME type: text/plain
File size: 12483 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1264 2006/06/25 11:08:04 debug Exp $
20060624	Replacing the error-prone machine type initialization stuff
		with something more reasonable.
		Finally removing the old "cpu_run" kludge; moving around stuff
		in machine.c and emul.c to better suit the dyntrans system.
		Various minor dyntrans cleanups (renaming translate_address to
		translate_v2p, and experimenting with template physpages).
20060625	Removing the speed hack which separated the vph entries into
		two halves (code vs data); things seem a lot more stable now.
		Minor performance hack: R2000/R3000 cache isolation now only
		clears address translations when going into isolation, not
		when going out of it.
		Fixing the MIPS interrupt problems by letting mtc0 immediately
		cause interrupts.

==============  RELEASE 0.4.0.1  ==============


1 /*
2 * Copyright (C) 2003-2005 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: memory_mips_v2p.c,v 1.6 2006/06/24 21:47:23 debug Exp $
29 *
30 * Included from memory.c.
31 */
32
33
34 /*
35 * translate_v2p():
36 *
37 * Don't call this function is userland_emul is non-NULL, or cpu is NULL.
38 *
39 * TODO: vpn2 is a bad name for R2K/R3K, as it is the actual framenumber.
40 *
41 * Return values:
42 * 0 Failure
43 * 1 Success, the page is readable only
44 * 2 Success, the page is read/write
45 */
46 int TRANSLATE_ADDRESS(struct cpu *cpu, uint64_t vaddr,
47 uint64_t *return_paddr, int flags)
48 {
49 int writeflag = flags & FLAG_WRITEFLAG? MEM_WRITE : MEM_READ;
50 int no_exceptions = flags & FLAG_NOEXCEPTIONS;
51 int ksu, use_tlb, status, i;
52 uint64_t vaddr_vpn2=0, vaddr_asid=0;
53 int exccode, tlb_refill;
54 struct mips_coproc *cp0;
55
56 #ifdef V2P_MMU3K
57 const int x_64 = 0;
58 const int n_tlbs = 64;
59 const int pmask = 0xfff;
60 #else
61 #ifdef V2P_MMU10K
62 const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK_R10K;
63 #else
64 #ifdef V2P_MMU4100
65 /* This is ugly */
66 const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK | 0x1800;
67 #else
68 const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK;
69 #endif
70 #endif
71 int x_64; /* non-zero for 64-bit address space accesses */
72 int pageshift, n_tlbs;
73 int pmask;
74 #ifdef V2P_MMU4100
75 const int pagemask_mask = PAGEMASK_MASK_R4100;
76 const int pagemask_shift = PAGEMASK_SHIFT_R4100;
77 const int pfn_shift = 10;
78 #else
79 const int pagemask_mask = PAGEMASK_MASK;
80 const int pagemask_shift = PAGEMASK_SHIFT;
81 const int pfn_shift = 12;
82 #endif
83 #endif /* !V2P_MMU3K */
84
85
86 exccode = -1;
87 tlb_refill = 1;
88
89 /* Cached values: */
90 cp0 = cpu->cd.mips.coproc[0];
91 status = cp0->reg[COP0_STATUS];
92
93 /*
94 * R4000 Address Translation:
95 *
96 * An address may be in one of the kernel segments, that
97 * are directly mapped, or the address can go through the
98 * TLBs to be turned into a physical address.
99 *
100 * KSU: EXL: ERL: X: Name: Range:
101 * ---- ---- ---- -- ----- ------
102 *
103 * 10 0 0 0 useg 0 - 0x7fffffff (2GB) (via TLB)
104 * 10 0 0 1 xuseg 0 - 0xffffffffff (1TB) (via TLB)
105 *
106 * 01 0 0 0 suseg 0 - 0x7fffffff (2GB via TLB)
107 * 01 0 0 0 ssseg 0xc0000000 - 0xdfffffff (0.5 GB via TLB)
108 * 01 0 0 1 xsuseg 0 - 0xffffffffff (1TB) (via TLB)
109 * 01 0 0 1 xsseg 0x4000000000000000 - 0x400000ffffffffff
110 * (1TB) (via TLB)
111 * 01 0 0 1 csseg 0xffffffffc0000000 - 0xffffffffdfffffff
112 * (0.5TB) (via TLB)
113 *
114 * 00 x x 0 kuseg 0 - 0x7fffffff (2GB) (via TLB) (*)
115 * 00 x x 0 kseg0 0x80000000 - 0x9fffffff (0.5GB)
116 * unmapped, cached
117 * 00 x x 0 kseg1 0xa0000000 - 0xbfffffff (0.5GB)
118 * unmapped, uncached
119 * 00 x x 0 ksseg 0xc0000000 - 0xdfffffff (0.5GB)
120 * (via TLB)
121 * 00 x x 0 kseg3 0xe0000000 - 0xffffffff (0.5GB)
122 * (via TLB)
123 * 00 x x 1 xksuseg 0 - 0xffffffffff (1TB) (via TLB) (*)
124 * 00 x x 1 xksseg 0x4000000000000000 - 0x400000ffffffffff
125 * (1TB) (via TLB)
126 * 00 x x 1 xkphys 0x8000000000000000 - 0xbfffffffffffffff
127 * todo
128 * 00 x x 1 xkseg 0xc000000000000000 - 0xc00000ff7fffffff
129 * todo
130 * 00 x x 1 ckseg0 0xffffffff80000000 - 0xffffffff9fffffff
131 * like kseg0
132 * 00 x x 1 ckseg1 0xffffffffa0000000 - 0xffffffffbfffffff
133 * like kseg1
134 * 00 x x 1 cksseg 0xffffffffc0000000 - 0xffffffffdfffffff
135 * like ksseg
136 * 00 x x 1 ckseg3 0xffffffffe0000000 - 0xffffffffffffffff
137 * like kseg2
138 *
139 * (*) = if ERL=1 then kuseg is not via TLB, but unmapped,
140 * uncached physical memory.
141 *
142 * (KSU==0 or EXL=1 or ERL=1 is enough to use k*seg*.)
143 *
144 * An invalid address causes an Address Error.
145 *
146 * See chapter 4, page 96, in the R4000 manual for more info!
147 */
148
149 #ifdef V2P_MMU3K
150 if (status & MIPS1_SR_KU_CUR)
151 ksu = KSU_USER;
152 else
153 ksu = KSU_KERNEL;
154
155 /* These are needed later: */
156 vaddr_asid = cp0->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK;
157 vaddr_vpn2 = vaddr & R2K3K_ENTRYHI_VPN_MASK;
158 #else
159 /*
160 * R4000 and others:
161 *
162 * kx,sx,ux = 0 for 32-bit addressing,
163 * 1 for 64-bit addressing.
164 */
165 n_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;
166
167 ksu = (status & STATUS_KSU_MASK) >> STATUS_KSU_SHIFT;
168 if (status & (STATUS_EXL | STATUS_ERL))
169 ksu = KSU_KERNEL;
170
171 /* Assume KSU_USER. */
172 x_64 = status & STATUS_UX;
173
174 if (ksu == KSU_KERNEL)
175 x_64 = status & STATUS_KX;
176 else if (ksu == KSU_SUPERVISOR)
177 x_64 = status & STATUS_SX;
178
179 /* This suppresses a compiler warning: */
180 pageshift = 12;
181
182 /*
183 * Physical addressing on R10000 etc:
184 *
185 * TODO: Probably only accessible in kernel mode.
186 *
187 * 0x9000000080000000 = disable L2 cache (?)
188 * TODO: Make this correct.
189 */
190 if ((vaddr >> 62) == 0x2) {
191 /*
192 * On IP30, addresses such as 0x900000001f600050 are used,
193 * but also things like 0x90000000a0000000. (TODO)
194 *
195 * On IP27 (and probably others), addresses such as
196 * 0x92... and 0x96... have to do with NUMA stuff.
197 */
198 *return_paddr = vaddr & (((uint64_t)1 << 44) - 1);
199 return 2;
200 }
201
202 /* This is needed later: */
203 vaddr_asid = cp0->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
204 /* vpn2 depends on pagemask, which is not fixed on R4000 */
205 #endif
206
207
208 if (vaddr <= 0x7fffffff)
209 use_tlb = 1;
210 else {
211 #if 1
212 /* TODO: This should be removed, but it seems that other
213 bugs are triggered. */
214 /* Sign-extend vaddr, if necessary: */
215 if ((vaddr >> 32) == 0 && vaddr & (uint32_t)0x80000000ULL)
216 vaddr |= 0xffffffff00000000ULL;
217 #endif
218 if (ksu == KSU_KERNEL) {
219 /* kseg0, kseg1: */
220 if (vaddr >= (uint64_t)0xffffffff80000000ULL &&
221 vaddr <= (uint64_t)0xffffffffbfffffffULL) {
222 *return_paddr = vaddr & 0x1fffffff;
223 return 2;
224 }
225
226 /* TODO: supervisor stuff */
227
228 /* other segments: */
229 use_tlb = 1;
230 } else
231 use_tlb = 0;
232 }
233
234 if (use_tlb) {
235 #ifndef V2P_MMU3K
236 int odd = 0;
237 uint64_t cached_lo1 = 0;
238 #endif
239 int g_bit, v_bit, d_bit;
240 uint64_t cached_hi, cached_lo0;
241 uint64_t entry_vpn2 = 0, entry_asid, pfn;
242
243 for (i=0; i<n_tlbs; i++) {
244 #ifdef V2P_MMU3K
245 /* R3000 or similar: */
246 cached_hi = cp0->tlbs[i].hi;
247 cached_lo0 = cp0->tlbs[i].lo0;
248
249 entry_vpn2 = cached_hi & R2K3K_ENTRYHI_VPN_MASK;
250 entry_asid = cached_hi & R2K3K_ENTRYHI_ASID_MASK;
251 g_bit = cached_lo0 & R2K3K_ENTRYLO_G;
252 v_bit = cached_lo0 & R2K3K_ENTRYLO_V;
253 d_bit = cached_lo0 & R2K3K_ENTRYLO_D;
254 #else
255 /* R4000 or similar: */
256 pmask = cp0->tlbs[i].mask & pagemask_mask;
257 cached_hi = cp0->tlbs[i].hi;
258 cached_lo0 = cp0->tlbs[i].lo0;
259 cached_lo1 = cp0->tlbs[i].lo1;
260
261 /* Optimized for minimum page size: */
262 if (pmask == 0) {
263 pageshift = pagemask_shift - 1;
264 entry_vpn2 = (cached_hi & vpn2_mask)
265 >> pagemask_shift;
266 vaddr_vpn2 = (vaddr & vpn2_mask)
267 >> pagemask_shift;
268 pmask = (1 << (pagemask_shift-1)) - 1;
269 odd = (vaddr >> (pagemask_shift-1)) & 1;
270 } else {
271 /* Non-standard page mask: */
272 switch (pmask | ((1 << pagemask_shift) - 1)) {
273 case 0x00007ff: pageshift = 10; break;
274 case 0x0001fff: pageshift = 12; break;
275 case 0x0007fff: pageshift = 14; break;
276 case 0x001ffff: pageshift = 16; break;
277 case 0x007ffff: pageshift = 18; break;
278 case 0x01fffff: pageshift = 20; break;
279 case 0x07fffff: pageshift = 22; break;
280 case 0x1ffffff: pageshift = 24; break;
281 case 0x7ffffff: pageshift = 26; break;
282 default:fatal("pmask=%08x\n", pmask);
283 exit(1);
284 }
285
286 entry_vpn2 = (cached_hi &
287 vpn2_mask) >> (pageshift + 1);
288 vaddr_vpn2 = (vaddr & vpn2_mask) >>
289 (pageshift + 1);
290 pmask = (1 << pageshift) - 1;
291 odd = (vaddr >> pageshift) & 1;
292 }
293
294 /* Assume even virtual page... */
295 v_bit = cached_lo0 & ENTRYLO_V;
296 d_bit = cached_lo0 & ENTRYLO_D;
297
298 #ifdef V2P_MMU8K
299 /*
300 * TODO: I don't really know anything about the R8000.
301 * http://futuretech.mirror.vuurwerk.net/i2sec7.html
302 * says that it has a three-way associative TLB with
303 * 384 entries, 16KB page size, and some other things.
304 *
305 * It feels like things like the valid bit (ala R4000)
306 * and dirty bit are not implemented the same on R8000.
307 *
308 * http://sgistuff.tastensuppe.de/documents/
309 * R8000_chipset.html
310 * also has some info, but no details.
311 */
312 v_bit = 1; /* Big TODO */
313 d_bit = 1;
314 #endif
315
316 entry_asid = cached_hi & ENTRYHI_ASID;
317
318 /* ... reload pfn, v_bit, d_bit if
319 it was the odd virtual page: */
320 if (odd) {
321 v_bit = cached_lo1 & ENTRYLO_V;
322 d_bit = cached_lo1 & ENTRYLO_D;
323 }
324 #ifdef V2P_MMU4100
325 g_bit = cached_lo1 & cached_lo0 & ENTRYLO_G;
326 #else
327 g_bit = cached_hi & TLB_G;
328 #endif
329
330 #endif
331
332 /* Is there a VPN and ASID match? */
333 if (entry_vpn2 == vaddr_vpn2 &&
334 (entry_asid == vaddr_asid || g_bit)) {
335 /* debug("OK MAP 1, i=%i { vaddr=%016"PRIx64" "
336 "==> paddr %016"PRIx64" v=%i d=%i "
337 "asid=0x%02x }\n", i, (uint64_t) vaddr,
338 (uint64_t) *return_paddr, v_bit?1:0,
339 d_bit?1:0, vaddr_asid); */
340 if (v_bit) {
341 if (d_bit || (!d_bit &&
342 writeflag == MEM_READ)) {
343 uint64_t paddr;
344 /* debug("OK MAP 2!!! { w=%i "
345 "vaddr=%016"PRIx64" ==> "
346 "d=%i v=%i paddr %016"
347 PRIx64" ",
348 writeflag, (uint64_t)vaddr,
349 d_bit?1:0, v_bit?1:0,
350 (uint64_t) *return_paddr);
351 debug(", tlb entry %2i: ma"
352 "sk=%016"PRIx64" hi=%016"
353 PRIx64" lo0=%016"PRIx64
354 " lo1=%016"PRIx64"\n",
355 i, cp0->tlbs[i].mask, cp0->
356 tlbs[i].hi, cp0->tlbs[i].
357 lo0, cp0->tlbs[i].lo1);
358 */
359 #ifdef V2P_MMU3K
360 pfn = cached_lo0 &
361 R2K3K_ENTRYLO_PFN_MASK;
362 paddr = pfn | (vaddr & pmask);
363 #else
364 pfn = ((odd? cached_lo1 :
365 cached_lo0)
366 & ENTRYLO_PFN_MASK)
367 >> ENTRYLO_PFN_SHIFT;
368 paddr = (pfn << pfn_shift) |
369 (vaddr & pmask);
370 #endif
371
372 *return_paddr = paddr;
373 return d_bit? 2 : 1;
374 } else {
375 /* TLB modif. exception */
376 tlb_refill = 0;
377 exccode = EXCEPTION_MOD;
378 goto exception;
379 }
380 } else {
381 /* TLB invalid exception */
382 tlb_refill = 0;
383 goto exception;
384 }
385 }
386 }
387 }
388
389 /*
390 * We are here if for example userland code tried to access
391 * kernel memory, OR if there was a TLB refill.
392 */
393
394 if (!use_tlb) {
395 tlb_refill = 0;
396 if (writeflag == MEM_WRITE)
397 exccode = EXCEPTION_ADES;
398 else
399 exccode = EXCEPTION_ADEL;
400 }
401
402 exception:
403 if (no_exceptions)
404 return 0;
405
406 /* TLB Load or Store exception: */
407 if (exccode == -1) {
408 if (writeflag == MEM_WRITE)
409 exccode = EXCEPTION_TLBS;
410 else
411 exccode = EXCEPTION_TLBL;
412 }
413
414 #ifdef V2P_MMU3K
415 vaddr_asid >>= R2K3K_ENTRYHI_ASID_SHIFT;
416 vaddr_vpn2 >>= 12;
417 #endif
418
419 mips_cpu_exception(cpu, exccode, tlb_refill, vaddr,
420 0, vaddr_vpn2, vaddr_asid, x_64);
421
422 /* Return failure: */
423 return 0;
424 }
425

  ViewVC Help
Powered by ViewVC 1.1.26