/[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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 6 months 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 dpavlin 14 /*
2 dpavlin 28 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 dpavlin 14 *
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 dpavlin 28 * $Id: memory_mips_v2p.c,v 1.7 2006/07/16 13:32:26 debug Exp $
29 dpavlin 14 */
30    
31    
32     /*
33 dpavlin 26 * translate_v2p():
34 dpavlin 14 *
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 dpavlin 26 uint64_t *return_paddr, int flags)
46 dpavlin 14 {
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 dpavlin 26 *return_paddr = vaddr & (((uint64_t)1 << 44) - 1);
197 dpavlin 14 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 dpavlin 26 *return_paddr = vaddr & 0x1fffffff;
221 dpavlin 14 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 dpavlin 22 int odd = 0;
235     uint64_t cached_lo1 = 0;
236 dpavlin 14 #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 dpavlin 20 default:fatal("pmask=%08x\n", pmask);
281 dpavlin 14 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 dpavlin 24 /* 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 dpavlin 26 (uint64_t) *return_paddr, v_bit?1:0,
337 dpavlin 14 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 dpavlin 24 "vaddr=%016"PRIx64" ==> "
344     "d=%i v=%i paddr %016"
345     PRIx64" ",
346     writeflag, (uint64_t)vaddr,
347 dpavlin 14 d_bit?1:0, v_bit?1:0,
348 dpavlin 26 (uint64_t) *return_paddr);
349 dpavlin 14 debug(", tlb entry %2i: ma"
350 dpavlin 24 "sk=%016"PRIx64" hi=%016"
351     PRIx64" lo0=%016"PRIx64
352     " lo1=%016"PRIx64"\n",
353 dpavlin 14 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 dpavlin 26 *return_paddr = paddr;
371 dpavlin 14 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