/[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 28 - (show annotations)
Mon Oct 8 16:20:26 2007 UTC (13 years, 1 month ago) by dpavlin
File MIME type: text/plain
File size: 12452 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26