/[gxemul]/trunk/src/cpus/memory_ppc.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_ppc.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (13 years, 3 months ago) by dpavlin
File MIME type: text/plain
File size: 8214 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     * Copyright (C) 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 dpavlin 28 * $Id: memory_ppc.c,v 1.25 2006/07/14 16:33:28 debug Exp $
29 dpavlin 14 *
30     * Included from cpu_ppc.c.
31     */
32    
33    
34 dpavlin 20 #include "ppc_bat.h"
35     #include "ppc_pte.h"
36    
37    
38 dpavlin 14 /*
39 dpavlin 20 * ppc_bat():
40     *
41     * BAT translation. Returns -1 if there was no BAT hit, >= 0 for a hit.
42     * (0 for access denied, 1 for read-only, and 2 for read-write access allowed.)
43     */
44 dpavlin 26 int ppc_bat(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr, int flags,
45 dpavlin 20 int user)
46     {
47 dpavlin 22 int i, istart = 0, iend = 8, pp;
48 dpavlin 20
49 dpavlin 22 if (flags & FLAG_INSTR)
50     iend = 4;
51     else
52     istart = 4;
53    
54 dpavlin 20 if (cpu->cd.ppc.bits != 32) {
55     fatal("TODO: ppc_bat() for non-32-bit\n");
56     exit(1);
57     }
58     if (cpu->cd.ppc.cpu_type.flags & PPC_601) {
59     fatal("TODO: ppc_bat() for PPC 601\n");
60     exit(1);
61     }
62    
63 dpavlin 22 /* Scan either the 4 instruction BATs or the 4 data BATs: */
64     for (i=istart; i<iend; i++) {
65     int regnr = SPR_IBAT0U + i * 2;
66 dpavlin 20 uint32_t upper = cpu->cd.ppc.spr[regnr];
67     uint32_t lower = cpu->cd.ppc.spr[regnr + 1];
68     uint32_t phys = lower & BAT_RPN, ebs = upper & BAT_EPI;
69     uint32_t mask = ((upper & BAT_BL) << 15) | 0x1ffff;
70    
71     /* Not valid in either supervisor or user mode? */
72     if (user && !(upper & BAT_Vu))
73     continue;
74     if (!user && !(upper & BAT_Vs))
75     continue;
76    
77     /* Virtual address mismatch? Then skip. */
78     if ((vaddr & ~mask) != (ebs & ~mask))
79     continue;
80    
81 dpavlin 26 *return_paddr = (vaddr & mask) | (phys & ~mask);
82 dpavlin 20
83     pp = lower & BAT_PP;
84     switch (pp) {
85     case BAT_PP_NONE:
86     return 0;
87     case BAT_PP_RO_S:
88     case BAT_PP_RO:
89     return (flags & FLAG_WRITEFLAG)? 0 : 1;
90     default:/* BAT_PP_RW: */
91     return 2;
92     }
93     }
94    
95     return -1;
96     }
97    
98    
99     /*
100     * get_pte_low():
101     *
102     * Scan a PTE group for a cmp (compare) value.
103     *
104     * Returns 1 if the value was found, and *lowp is set to the low PTE word.
105     * Returns 0 if no match was found.
106     */
107     static int get_pte_low(struct cpu *cpu, uint64_t pteg_select,
108     uint32_t *lowp, uint32_t cmp)
109     {
110 dpavlin 28 unsigned char *d = memory_paddr_to_hostaddr(cpu->mem, pteg_select, 1);
111 dpavlin 20 int i;
112    
113     for (i=0; i<8; i++) {
114 dpavlin 22 uint32_t *ep = (uint32_t *) (d + (i << 3)), upper;
115     upper = *ep;
116     upper = BE32_TO_HOST(upper);
117 dpavlin 20
118     /* Valid PTE, and correct api and vsid? */
119     if (upper == cmp) {
120 dpavlin 22 uint32_t lo = ep[1];
121     lo = BE32_TO_HOST(lo);
122     *lowp = lo;
123 dpavlin 20 return 1;
124     }
125     }
126    
127     return 0;
128     }
129    
130    
131     /*
132     * ppc_vtp32():
133     *
134     * Virtual to physical address translation (32-bit mode).
135     *
136     * Returns 1 if a translation was found, 0 if none was found. However, finding
137     * a translation does not mean that it should be returned; there can be
138     * a permission violation. *resp is set to 0 for no access, 1 for read-only
139     * access, or 2 for read/write access.
140     */
141 dpavlin 26 static int ppc_vtp32(struct cpu *cpu, uint32_t vaddr, uint64_t *return_paddr,
142 dpavlin 20 int *resp, uint64_t msr, int writeflag, int instr)
143     {
144     int srn = (vaddr >> 28) & 15, api = (vaddr >> 22) & PTE_API;
145     int access, key, match;
146     uint32_t vsid = cpu->cd.ppc.sr[srn] & 0x00ffffff;
147     uint64_t sdr1 = cpu->cd.ppc.spr[SPR_SDR1], htaborg;
148     uint32_t hash1, hash2, pteg_select, tmp;
149     uint32_t lower_pte = 0, cmp;
150    
151     htaborg = sdr1 & 0xffff0000UL;
152    
153     /* Primary hash: */
154     hash1 = (vsid & 0x7ffff) ^ ((vaddr >> 12) & 0xffff);
155     tmp = (hash1 >> 10) & (sdr1 & 0x1ff);
156     pteg_select = htaborg & 0xfe000000;
157     pteg_select |= ((hash1 & 0x3ff) << 6);
158     pteg_select |= (htaborg & 0x01ff0000) | (tmp << 16);
159     cpu->cd.ppc.spr[SPR_HASH1] = pteg_select;
160     cmp = cpu->cd.ppc.spr[instr? SPR_ICMP : SPR_DCMP] =
161     PTE_VALID | api | (vsid << PTE_VSID_SHFT);
162     match = get_pte_low(cpu, pteg_select, &lower_pte, cmp);
163    
164     /* Secondary hash: */
165     hash2 = hash1 ^ 0x7ffff;
166     tmp = (hash2 >> 10) & (sdr1 & 0x1ff);
167     pteg_select = htaborg & 0xfe000000;
168     pteg_select |= ((hash2 & 0x3ff) << 6);
169     pteg_select |= (htaborg & 0x01ff0000) | (tmp << 16);
170     cpu->cd.ppc.spr[SPR_HASH2] = pteg_select;
171     if (!match) {
172     cmp |= PTE_HID;
173     match = get_pte_low(cpu, pteg_select, &lower_pte, cmp);
174     }
175    
176     *resp = 0;
177    
178     if (!match)
179     return 0;
180    
181     /* Non-executable, or Guarded page? */
182     if (instr && cpu->cd.ppc.sr[srn] & SR_NOEXEC)
183     return 1;
184     if (instr && lower_pte & PTE_G)
185     return 1;
186    
187     access = lower_pte & PTE_PP;
188 dpavlin 26 *return_paddr = (lower_pte & PTE_RPGN) | (vaddr & ~PTE_RPGN);
189 dpavlin 20
190     key = (cpu->cd.ppc.sr[srn] & SR_PRKEY && msr & PPC_MSR_PR) ||
191     (cpu->cd.ppc.sr[srn] & SR_SUKEY && !(msr & PPC_MSR_PR));
192    
193     if (key) {
194     switch (access) {
195     case 1:
196     case 3: *resp = writeflag? 0 : 1;
197     break;
198     case 2: *resp = 2;
199     break;
200     }
201     } else {
202     switch (access) {
203     case 3: *resp = writeflag? 0 : 1;
204     break;
205     default:*resp = 2;
206     }
207     }
208    
209     return 1;
210     }
211    
212    
213     /*
214 dpavlin 26 * ppc_translate_v2p():
215 dpavlin 14 *
216     * Don't call this function is userland_emul is non-NULL, or cpu is NULL.
217     *
218     * Return values:
219     * 0 Failure
220     * 1 Success, the page is readable only
221     * 2 Success, the page is read/write
222     */
223 dpavlin 26 int ppc_translate_v2p(struct cpu *cpu, uint64_t vaddr,
224     uint64_t *return_paddr, int flags)
225 dpavlin 14 {
226 dpavlin 20 int instr = flags & FLAG_INSTR, res = 0, match, user;
227     int writeflag = flags & FLAG_WRITEFLAG? 1 : 0;
228     uint64_t msr;
229 dpavlin 14
230 dpavlin 20 reg_access_msr(cpu, &msr, 0, 0);
231     user = msr & PPC_MSR_PR? 1 : 0;
232    
233 dpavlin 14 if (cpu->cd.ppc.bits == 32)
234     vaddr &= 0xffffffff;
235    
236 dpavlin 20 if ((instr && !(msr & PPC_MSR_IR)) || (!instr && !(msr & PPC_MSR_DR))) {
237 dpavlin 26 *return_paddr = vaddr;
238 dpavlin 14 return 2;
239     }
240    
241 dpavlin 20 if (cpu->cd.ppc.cpu_type.flags & PPC_601) {
242 dpavlin 26 fatal("ppc_translate_v2p(): TODO: 601\n");
243 dpavlin 20 exit(1);
244     }
245 dpavlin 14
246 dpavlin 20 /* Try the BATs first: */
247     if (cpu->cd.ppc.bits == 32) {
248 dpavlin 26 res = ppc_bat(cpu, vaddr, return_paddr, flags, user);
249 dpavlin 20 if (res > 0)
250     return res;
251     if (res == 0) {
252     fatal("[ TODO: BAT exception ]\n");
253     exit(1);
254 dpavlin 14 }
255 dpavlin 20 }
256 dpavlin 14
257 dpavlin 20 /* Virtual to physical translation: */
258     if (cpu->cd.ppc.bits == 32) {
259 dpavlin 26 match = ppc_vtp32(cpu, vaddr, return_paddr, &res, msr,
260 dpavlin 20 writeflag, instr);
261     if (match && res > 0)
262     return res;
263     } else {
264     /* htaborg = sdr1 & 0xfffffffffffc0000ULL; */
265     fatal("TODO: ppc 64-bit translation\n");
266     exit(1);
267 dpavlin 14 }
268    
269 dpavlin 20
270     /*
271     * No match? Then cause an exception.
272     *
273     * PPC603: cause a software TLB reload exception.
274     * All others: cause a DSI or ISI.
275     */
276    
277 dpavlin 14 if (flags & FLAG_NOEXCEPTIONS)
278     return 0;
279    
280 dpavlin 20 if (!quiet_mode)
281 dpavlin 24 fatal("[ memory_ppc: exception! vaddr=0x%"PRIx64" pc=0x%"PRIx64
282     " instr=%i user=%i wf=%i ]\n", (uint64_t) vaddr,
283     (uint64_t) cpu->pc, instr, user, writeflag);
284 dpavlin 20
285     if (cpu->cd.ppc.cpu_type.flags & PPC_603) {
286     cpu->cd.ppc.spr[instr? SPR_IMISS : SPR_DMISS] = vaddr;
287    
288     msr |= PPC_MSR_TGPR;
289     reg_access_msr(cpu, &msr, 1, 0);
290    
291     ppc_exception(cpu, instr? 0x10 : (writeflag? 0x12 : 0x11));
292     } else {
293     if (!instr) {
294     cpu->cd.ppc.spr[SPR_DAR] = vaddr;
295     cpu->cd.ppc.spr[SPR_DSISR] = match?
296     DSISR_PROTECT : DSISR_NOTFOUND;
297     if (writeflag)
298     cpu->cd.ppc.spr[SPR_DSISR] |= DSISR_STORE;
299     }
300     ppc_exception(cpu, instr?
301     PPC_EXCEPTION_ISI : PPC_EXCEPTION_DSI);
302     }
303    
304 dpavlin 14 return 0;
305     }
306    

  ViewVC Help
Powered by ViewVC 1.1.26