/[gxemul]/upstream/0.3.3.2/src/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 /upstream/0.3.3.2/src/memory_mips_v2p.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 9 - (show annotations)
Mon Oct 8 16:18:22 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 14035 byte(s)
0.3.3.2
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.4 2005/02/18 07:11:56 debug Exp $
29 *
30 * Included from memory.c.
31 */
32
33
34 /*
35 * translate_address():
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_addr, int flags)
48 {
49 int writeflag = flags & FLAG_WRITEFLAG? MEM_WRITE : MEM_READ;
50 int no_exceptions = flags & FLAG_NOEXCEPTIONS;
51 int instr = flags & FLAG_INSTR;
52 int ksu, use_tlb, status, i;
53 uint64_t vaddr_vpn2=0, vaddr_asid=0;
54 int exccode, tlb_refill;
55 struct mips_coproc *cp0;
56 int bintrans_cached = cpu->machine->bintrans_enable;
57
58 #ifdef V2P_MMU3K
59 const int x_64 = 0;
60 const int n_tlbs = 64;
61 const int pmask = 0xfff;
62 #else
63 #ifdef V2P_MMU10K
64 const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK_R10K;
65 #else
66 #ifdef V2P_MMU4100
67 /* This is ugly */
68 const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK | 0x1800;
69 #else
70 const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK;
71 #endif
72 #endif
73 int x_64; /* non-zero for 64-bit address space accesses */
74 int pageshift, n_tlbs;
75 int pmask;
76 #ifdef V2P_MMU4100
77 const int pagemask_mask = PAGEMASK_MASK_R4100;
78 const int pagemask_shift = PAGEMASK_SHIFT_R4100;
79 const int pfn_shift = 10;
80 #else
81 const int pagemask_mask = PAGEMASK_MASK;
82 const int pagemask_shift = PAGEMASK_SHIFT;
83 const int pfn_shift = 12;
84 #endif
85 #endif /* !V2P_MMU3K */
86
87
88 #ifdef USE_TINY_CACHE
89 /*
90 * Check the tiny translation cache first:
91 *
92 * Only userland addresses are checked, because other addresses
93 * are probably better of being statically translated, or through
94 * the TLB. (Note: When running with 64-bit addresses, this
95 * will still produce the correct result. At worst, we check the
96 * cache in vain, but the result should still be correct.)
97 */
98 if (!bintrans_cached &&
99 (vaddr & 0xc0000000ULL) != 0x80000000ULL) {
100 int i, wf = 1 + (writeflag == MEM_WRITE);
101 uint64_t vaddr_shift_12 = vaddr >> 12;
102
103 if (instr) {
104 /* Code: */
105 for (i=0; i<N_TRANSLATION_CACHE_INSTR; i++) {
106 if (cpu->cd.mips.translation_cache_instr[i].wf
107 >= wf && vaddr_shift_12 == (cpu->cd.mips.
108 translation_cache_instr[i].vaddr_pfn)) {
109 *return_addr = cpu->cd.mips.
110 translation_cache_instr[i].paddr
111 | (vaddr & 0xfff);
112 return cpu->cd.mips.
113 translation_cache_instr[i].wf;
114 }
115 }
116 } else {
117 /* Data: */
118 for (i=0; i<N_TRANSLATION_CACHE_DATA; i++) {
119 if (cpu->cd.mips.translation_cache_data[i].wf
120 >= wf && vaddr_shift_12 == (cpu->cd.mips.
121 translation_cache_data[i].vaddr_pfn)) {
122 *return_addr = cpu->cd.mips.
123 translation_cache_data[i].paddr
124 | (vaddr & 0xfff);
125 return cpu->cd.mips.
126 translation_cache_data[i].wf;
127 }
128 }
129 }
130 }
131 #endif
132
133 exccode = -1;
134 tlb_refill = 1;
135
136 /* Cached values: */
137 cp0 = cpu->cd.mips.coproc[0];
138 status = cp0->reg[COP0_STATUS];
139
140 /*
141 * R4000 Address Translation:
142 *
143 * An address may be in one of the kernel segments, that
144 * are directly mapped, or the address can go through the
145 * TLBs to be turned into a physical address.
146 *
147 * KSU: EXL: ERL: X: Name: Range:
148 * ---- ---- ---- -- ----- ------
149 *
150 * 10 0 0 0 useg 0 - 0x7fffffff (2GB) (via TLB)
151 * 10 0 0 1 xuseg 0 - 0xffffffffff (1TB) (via TLB)
152 *
153 * 01 0 0 0 suseg 0 - 0x7fffffff (2GB via TLB)
154 * 01 0 0 0 ssseg 0xc0000000 - 0xdfffffff (0.5 GB via TLB)
155 * 01 0 0 1 xsuseg 0 - 0xffffffffff (1TB) (via TLB)
156 * 01 0 0 1 xsseg 0x4000000000000000 - 0x400000ffffffffff
157 * (1TB) (via TLB)
158 * 01 0 0 1 csseg 0xffffffffc0000000 - 0xffffffffdfffffff
159 * (0.5TB) (via TLB)
160 *
161 * 00 x x 0 kuseg 0 - 0x7fffffff (2GB) (via TLB) (*)
162 * 00 x x 0 kseg0 0x80000000 - 0x9fffffff (0.5GB)
163 * unmapped, cached
164 * 00 x x 0 kseg1 0xa0000000 - 0xbfffffff (0.5GB)
165 * unmapped, uncached
166 * 00 x x 0 ksseg 0xc0000000 - 0xdfffffff (0.5GB)
167 * (via TLB)
168 * 00 x x 0 kseg3 0xe0000000 - 0xffffffff (0.5GB)
169 * (via TLB)
170 * 00 x x 1 xksuseg 0 - 0xffffffffff (1TB) (via TLB) (*)
171 * 00 x x 1 xksseg 0x4000000000000000 - 0x400000ffffffffff
172 * (1TB) (via TLB)
173 * 00 x x 1 xkphys 0x8000000000000000 - 0xbfffffffffffffff
174 * todo
175 * 00 x x 1 xkseg 0xc000000000000000 - 0xc00000ff7fffffff
176 * todo
177 * 00 x x 1 ckseg0 0xffffffff80000000 - 0xffffffff9fffffff
178 * like kseg0
179 * 00 x x 1 ckseg1 0xffffffffa0000000 - 0xffffffffbfffffff
180 * like kseg1
181 * 00 x x 1 cksseg 0xffffffffc0000000 - 0xffffffffdfffffff
182 * like ksseg
183 * 00 x x 1 ckseg3 0xffffffffe0000000 - 0xffffffffffffffff
184 * like kseg2
185 *
186 * (*) = if ERL=1 then kuseg is not via TLB, but unmapped,
187 * uncached physical memory.
188 *
189 * (KSU==0 or EXL=1 or ERL=1 is enough to use k*seg*.)
190 *
191 * An invalid address causes an Address Error.
192 *
193 * See chapter 4, page 96, in the R4000 manual for more info!
194 */
195
196 #ifdef V2P_MMU3K
197 if (status & MIPS1_SR_KU_CUR)
198 ksu = KSU_USER;
199 else
200 ksu = KSU_KERNEL;
201
202 /* These are needed later: */
203 vaddr_asid = cp0->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK;
204 vaddr_vpn2 = vaddr & R2K3K_ENTRYHI_VPN_MASK;
205 #else
206 /*
207 * R4000 and others:
208 *
209 * kx,sx,ux = 0 for 32-bit addressing,
210 * 1 for 64-bit addressing.
211 */
212 n_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;
213
214 ksu = (status & STATUS_KSU_MASK) >> STATUS_KSU_SHIFT;
215 if (status & (STATUS_EXL | STATUS_ERL))
216 ksu = KSU_KERNEL;
217
218 /* Assume KSU_USER. */
219 x_64 = status & STATUS_UX;
220
221 if (ksu == KSU_KERNEL)
222 x_64 = status & STATUS_KX;
223 else if (ksu == KSU_SUPERVISOR)
224 x_64 = status & STATUS_SX;
225
226 /* This suppresses a compiler warning: */
227 pageshift = 12;
228
229 /*
230 * Physical addressing on R10000 etc:
231 *
232 * TODO: Probably only accessible in kernel mode.
233 *
234 * 0x9000000080000000 = disable L2 cache (?)
235 * TODO: Make this correct.
236 */
237 if ((vaddr >> 62) == 0x2) {
238 /*
239 * On IP30, addresses such as 0x900000001f600050 are used,
240 * but also things like 0x90000000a0000000. (TODO)
241 *
242 * On IP27 (and probably others), addresses such as
243 * 0x92... and 0x96... have to do with NUMA stuff.
244 */
245 *return_addr = vaddr & (((uint64_t)1 << 44) - 1);
246 return 2;
247 }
248
249 /* This is needed later: */
250 vaddr_asid = cp0->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
251 /* vpn2 depends on pagemask, which is not fixed on R4000 */
252 #endif
253
254
255 if (vaddr <= 0x7fffffff)
256 use_tlb = 1;
257 else {
258 #if 1
259 /* TODO: This should be removed, but it seems that other
260 bugs are triggered. */
261 /* Sign-extend vaddr, if necessary: */
262 if ((vaddr >> 32) == 0 && vaddr & (uint32_t)0x80000000ULL)
263 vaddr |= 0xffffffff00000000ULL;
264 #endif
265 if (ksu == KSU_KERNEL) {
266 /* kseg0, kseg1: */
267 if (vaddr >= (uint64_t)0xffffffff80000000ULL &&
268 vaddr <= (uint64_t)0xffffffffbfffffffULL) {
269 *return_addr = vaddr & 0x1fffffff;
270 return 2;
271 }
272
273 /* TODO: supervisor stuff */
274
275 /* other segments: */
276 use_tlb = 1;
277 } else
278 use_tlb = 0;
279 }
280
281 if (use_tlb) {
282 #ifndef V2P_MMU3K
283 int odd = 0, cached_lo1 = 0;
284 #endif
285 int g_bit, v_bit, d_bit;
286 uint64_t cached_hi, cached_lo0;
287 uint64_t entry_vpn2 = 0, entry_asid, pfn;
288
289 for (i=0; i<n_tlbs; i++) {
290 #ifdef V2P_MMU3K
291 /* R3000 or similar: */
292 cached_hi = cp0->tlbs[i].hi;
293 cached_lo0 = cp0->tlbs[i].lo0;
294
295 entry_vpn2 = cached_hi & R2K3K_ENTRYHI_VPN_MASK;
296 entry_asid = cached_hi & R2K3K_ENTRYHI_ASID_MASK;
297 g_bit = cached_lo0 & R2K3K_ENTRYLO_G;
298 v_bit = cached_lo0 & R2K3K_ENTRYLO_V;
299 d_bit = cached_lo0 & R2K3K_ENTRYLO_D;
300 #else
301 /* R4000 or similar: */
302 pmask = cp0->tlbs[i].mask & pagemask_mask;
303 cached_hi = cp0->tlbs[i].hi;
304 cached_lo0 = cp0->tlbs[i].lo0;
305 cached_lo1 = cp0->tlbs[i].lo1;
306
307 /* Optimized for minimum page size: */
308 if (pmask == 0) {
309 pageshift = pagemask_shift - 1;
310 entry_vpn2 = (cached_hi & vpn2_mask)
311 >> pagemask_shift;
312 vaddr_vpn2 = (vaddr & vpn2_mask)
313 >> pagemask_shift;
314 pmask = (1 << (pagemask_shift-1)) - 1;
315 odd = (vaddr >> (pagemask_shift-1)) & 1;
316 } else {
317 /* Non-standard page mask: */
318 switch (pmask | ((1 << pagemask_shift) - 1)) {
319 case 0x00007ff: pageshift = 10; break;
320 case 0x0001fff: pageshift = 12; break;
321 case 0x0007fff: pageshift = 14; break;
322 case 0x001ffff: pageshift = 16; break;
323 case 0x007ffff: pageshift = 18; break;
324 case 0x01fffff: pageshift = 20; break;
325 case 0x07fffff: pageshift = 22; break;
326 case 0x1ffffff: pageshift = 24; break;
327 case 0x7ffffff: pageshift = 26; break;
328 default:
329 fatal("pmask=%08x\n", i, pmask);
330 exit(1);
331 }
332
333 entry_vpn2 = (cached_hi &
334 vpn2_mask) >> (pageshift + 1);
335 vaddr_vpn2 = (vaddr & vpn2_mask) >>
336 (pageshift + 1);
337 pmask = (1 << pageshift) - 1;
338 odd = (vaddr >> pageshift) & 1;
339 }
340
341 /* Assume even virtual page... */
342 v_bit = cached_lo0 & ENTRYLO_V;
343 d_bit = cached_lo0 & ENTRYLO_D;
344
345 #ifdef V2P_MMU8K
346 /*
347 * TODO: I don't really know anything about the R8000.
348 * http://futuretech.mirror.vuurwerk.net/i2sec7.html
349 * says that it has a three-way associative TLB with
350 * 384 entries, 16KB page size, and some other things.
351 *
352 * It feels like things like the valid bit (ala R4000)
353 * and dirty bit are not implemented the same on R8000.
354 *
355 * http://sgistuff.tastensuppe.de/documents/
356 * R8000_chipset.html
357 * also has some info, but no details.
358 */
359 v_bit = 1; /* Big TODO */
360 d_bit = 1;
361 #endif
362
363 entry_asid = cached_hi & ENTRYHI_ASID;
364
365 /* ... reload pfn, v_bit, d_bit if
366 it was the odd virtual page: */
367 if (odd) {
368 v_bit = cached_lo1 & ENTRYLO_V;
369 d_bit = cached_lo1 & ENTRYLO_D;
370 }
371 #ifdef V2P_MMU4100
372 g_bit = cached_lo1 & cached_lo0 & ENTRYLO_G;
373 #else
374 g_bit = cached_hi & TLB_G;
375 #endif
376
377 #endif
378
379 /* Is there a VPN and ASID match? */
380 if (entry_vpn2 == vaddr_vpn2 &&
381 (entry_asid == vaddr_asid || g_bit)) {
382 /* debug("OK MAP 1, i=%i { vaddr=%016llx "
383 "==> paddr %016llx v=%i d=%i "
384 "asid=0x%02x }\n", i, (long long)vaddr,
385 (long long) *return_addr, v_bit?1:0,
386 d_bit?1:0, vaddr_asid); */
387 if (v_bit) {
388 if (d_bit || (!d_bit &&
389 writeflag == MEM_READ)) {
390 uint64_t paddr;
391 /* debug("OK MAP 2!!! { w=%i "
392 "vaddr=%016llx ==> d=%i v="
393 "%i paddr %016llx ",
394 writeflag, (long long)vaddr,
395 d_bit?1:0, v_bit?1:0,
396 (long long) *return_addr);
397 debug(", tlb entry %2i: ma"
398 "sk=%016llx hi=%016llx lo0"
399 "=%016llx lo1=%016llx\n",
400 i, cp0->tlbs[i].mask, cp0->
401 tlbs[i].hi, cp0->tlbs[i].
402 lo0, cp0->tlbs[i].lo1);
403 */
404 #ifdef V2P_MMU3K
405 pfn = cached_lo0 &
406 R2K3K_ENTRYLO_PFN_MASK;
407 paddr = pfn | (vaddr & pmask);
408 #else
409 pfn = ((odd? cached_lo1 :
410 cached_lo0)
411 & ENTRYLO_PFN_MASK)
412 >> ENTRYLO_PFN_SHIFT;
413 paddr = (pfn << pfn_shift) |
414 (vaddr & pmask);
415 #endif
416
417 /*
418 * Enter into the tiny trans-
419 * lation cache (if enabled)
420 * and return:
421 */
422 if (!bintrans_cached)
423 insert_into_tiny_cache(
424 cpu, instr, d_bit?
425 MEM_WRITE :
426 MEM_READ,
427 vaddr, paddr);
428
429 *return_addr = paddr;
430 return d_bit? 2 : 1;
431 } else {
432 /* TLB modif. exception */
433 tlb_refill = 0;
434 exccode = EXCEPTION_MOD;
435 goto exception;
436 }
437 } else {
438 /* TLB invalid exception */
439 tlb_refill = 0;
440 goto exception;
441 }
442 }
443 }
444 }
445
446 /*
447 * We are here if for example userland code tried to access
448 * kernel memory.
449 */
450
451 /* TLB refill */
452
453 exception:
454 if (no_exceptions)
455 return 0;
456
457 /* TLB Load or Store exception: */
458 if (exccode == -1) {
459 if (writeflag == MEM_WRITE)
460 exccode = EXCEPTION_TLBS;
461 else
462 exccode = EXCEPTION_TLBL;
463 }
464
465 #ifdef V2P_MMU3K
466 vaddr_asid >>= R2K3K_ENTRYHI_ASID_SHIFT;
467 vaddr_vpn2 >>= 12;
468 #endif
469
470 mips_cpu_exception(cpu, exccode, tlb_refill, vaddr,
471 0, vaddr_vpn2, vaddr_asid, x_64);
472
473 /* Return failure: */
474 return 0;
475 }
476

  ViewVC Help
Powered by ViewVC 1.1.26