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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26