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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (show annotations)
Mon Oct 8 16:21:34 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 8324 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1497 2007/03/18 03:41:36 debug Exp $
20070224	Minor update to the initialization of the ns16550 in
		machine_walnut.c, to allow that machine type to boot with the
		new interrupt system (although it is still a dummy machine).
		Adding a wdc at 0x14000000 to machine_landisk.c, and fixing
		the SCIF serial interrupts of the SH4 cpu enough to get
		NetBSD/landisk booting from a disk image :-)  Adding a
		preliminary install instruction skeleton to guestoses.html.
20070306	Adding SH-IPL+G PROM emulation, and also passing the "end"
		symbol in r5 on bootup, for Landisk emulation. This is enough
		to get OpenBSD/landisk to install :)  Adding a preliminary
		install instruction skeleton to the documentation. SuperH
		emulation is still shaky, though :-/
20070307	Fixed a strangeness in memory_sh.c (read/write was never
		returned for any page). (Unknown whether this fixes any actual
		problems, though.)
20070308	dev_ram.c fix: invalidate code translations on writes to
		RAM, emulated as separate devices. Linux/dreamcast gets
		further in the boot process than before, but still bugs out
		in userland.
		Fixing bugs in the "stc.l gbr,@-rN" and "ldc.l @rN+,gbr" SuperH 
		instructions (they should NOT check the MD bit), allowing the
		Linux/dreamcast Live CD to reach userland correctly :-)
20070310	Changing the cpu name "Alpha" in src/useremul.c to "21364" to
		unbreak userland syscall emulation of FreeBSD/Alpha binaries.
20070314	Applying a patch from Michael Yaroslavtsev which fixes the
		previous Linux lib64 patch to the configure script.
20070315	Adding a (dummy) sun4v machine type, and SPARC T1 cpu type.
20070316	Creating a new directory, src/disk, and moving diskimage.c
		to it. Separating out bootblock loading stuff from emul.c into
		new files in src/disk.
		Adding some more SPARC registers.
20070318	Preparing/testing for a minirelease, 0.4.4.1.

==============  RELEASE 0.4.4.1  ==============


1 /*
2 * Copyright (C) 2006-2007 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_sh.c,v 1.16 2007/03/08 10:02:32 debug Exp $
29 */
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 #include "cpu.h"
36 #include "machine.h"
37 #include "memory.h"
38 #include "misc.h"
39
40 #include "sh4_exception.h"
41 #include "sh4_mmu.h"
42
43
44 /*
45 * translate_via_mmu():
46 *
47 * Scan the UTLB for a matching virtual address. If a match was found, then
48 * check permission bits etc. If everything was ok, then return the physical
49 * page address, otherwise cause an exception.
50 *
51 * The implementation should (hopefully) be quite complete, except for lack
52 * of "Multiple matching entries" detection. (On a real CPU, these would
53 * cause exceptions.)
54 *
55 * Same return values as sh_translate_v2p().
56 */
57 static int translate_via_mmu(struct cpu *cpu, uint32_t vaddr,
58 uint64_t *return_paddr, int flags)
59 {
60 int wf = flags & FLAG_WRITEFLAG;
61 int i, urb, urc, require_asid_match, cur_asid, expevt = 0;
62 uint32_t hi, lo = 0, mask = 0;
63 int sh; /* Shared */
64 int d; /* Dirty bit */
65 int v; /* Valid bit */
66 int pr; /* Protection */
67 int i_start;
68
69 cur_asid = cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK;
70 require_asid_match = !(cpu->cd.sh.mmucr & SH4_MMUCR_SV)
71 || !(cpu->cd.sh.sr & SH_SR_MD);
72
73 if (!(flags & FLAG_NOEXCEPTIONS)) {
74 /*
75 * Increase URC every time the UTLB is accessed. (Note:
76 * According to the SH4 manual, the URC should not be
77 * increased when running the ldtlb instruction. Perhaps this
78 * is a good place? Perhaps it is better to just set it to a
79 * random value? TODO: Find out.
80 */
81 urb = (cpu->cd.sh.mmucr & SH4_MMUCR_URB_MASK) >>
82 SH4_MMUCR_URB_SHIFT;
83 urc = (cpu->cd.sh.mmucr & SH4_MMUCR_URC_MASK) >>
84 SH4_MMUCR_URC_SHIFT;
85
86 /* fatal("urc = %i ==> ", urc); */
87 urc ++;
88 if (urc >= SH_N_UTLB_ENTRIES || (urb > 0 && urc == urb))
89 urc = 0;
90 /* fatal("%i\n", urc); */
91
92 cpu->cd.sh.mmucr &= ~SH4_MMUCR_URC_MASK;
93 cpu->cd.sh.mmucr |= (urc << SH4_MMUCR_URC_SHIFT);
94 }
95
96 /*
97 * When doing Instruction lookups, the ITLB should be scanned first.
98 * This is done by using negative i. (Ugly hack, but works.)
99 */
100 if (flags & FLAG_INSTR)
101 i_start = -SH_N_ITLB_ENTRIES;
102 else
103 i_start = 0;
104
105 for (i=i_start; i<SH_N_UTLB_ENTRIES; i++) {
106 if (i<0) {
107 hi = cpu->cd.sh.itlb_hi[i + SH_N_ITLB_ENTRIES];
108 lo = cpu->cd.sh.itlb_lo[i + SH_N_ITLB_ENTRIES];
109 } else {
110 hi = cpu->cd.sh.utlb_hi[i];
111 lo = cpu->cd.sh.utlb_lo[i];
112 }
113 mask = 0xfff00000;
114
115 v = lo & SH4_PTEL_V;
116
117 switch (lo & SH4_PTEL_SZ_MASK) {
118 case SH4_PTEL_SZ_1K: mask = 0xfffffc00; break;
119 case SH4_PTEL_SZ_4K: mask = 0xfffff000; break;
120 case SH4_PTEL_SZ_64K: mask = 0xffff0000; break;
121 /* case SH4_PTEL_SZ_1M: mask = 0xfff00000; break; */
122 }
123
124 if (!v || (hi & mask) != (vaddr & mask))
125 continue;
126
127 sh = lo & SH4_PTEL_SH;
128
129 if (!sh && require_asid_match) {
130 int asid = hi & SH4_PTEH_ASID_MASK;
131 if (asid != cur_asid)
132 continue;
133 }
134
135 /* Note/TODO: Check for multiple matches is not implemented. */
136
137 break;
138 }
139
140 /* Virtual address not found? Then it's a TLB miss. */
141 if (i == SH_N_UTLB_ENTRIES)
142 goto tlb_miss;
143
144 /* Matching address found! Let's see whether it is
145 readable/writable, etc.: */
146 d = lo & SH4_PTEL_D? 1 : 0;
147 pr = (lo & SH4_PTEL_PR_MASK) >> SH4_PTEL_PR_SHIFT;
148
149 *return_paddr = (vaddr & ~mask) | (lo & mask & 0x1fffffff);
150
151 if (flags & FLAG_INSTR) {
152 /*
153 * Instruction access:
154 *
155 * If a matching entry wasn't found in the ITLB, but in the
156 * UTLB, then copy it to a random place in the ITLB.
157 */
158 if (i >= 0) {
159 int r = random() % SH_N_ITLB_ENTRIES;
160
161 /* NOTE: Make sure that the old mapping for
162 that itlb entry is invalidated: */
163 cpu->invalidate_translation_caches(cpu,
164 cpu->cd.sh.itlb_hi[r] & ~0xfff, INVALIDATE_VADDR);
165
166 cpu->invalidate_code_translation(cpu,
167 cpu->cd.sh.utlb_lo[i] & ~0xfff, INVALIDATE_PADDR);
168
169 cpu->cd.sh.itlb_hi[r] = cpu->cd.sh.utlb_hi[i];
170 cpu->cd.sh.itlb_lo[r] = cpu->cd.sh.utlb_lo[i];
171 }
172
173 /* Permission checks: */
174 if (cpu->cd.sh.sr & SH_SR_MD)
175 return 1;
176 if (!(pr & 2))
177 goto protection_violation;
178
179 return 1;
180 }
181
182 /* Data access: */
183 if (cpu->cd.sh.sr & SH_SR_MD) {
184 /* Kernel access: */
185 switch (pr) {
186 case 0:
187 case 2: if (wf)
188 goto protection_violation;
189 return 1;
190 case 1:
191 case 3: if (wf && !d)
192 goto initial_write_exception;
193 return 1 + d;
194 }
195 }
196
197 /* User access */
198 switch (pr) {
199 case 0:
200 case 1: goto protection_violation;
201 case 2: if (wf)
202 goto protection_violation;
203 return 1;
204 case 3: if (wf && !d)
205 goto initial_write_exception;
206 return 1 + d;
207 }
208
209
210 tlb_miss:
211 expevt = wf? EXPEVT_TLB_MISS_ST : EXPEVT_TLB_MISS_LD;
212 goto exception;
213
214 protection_violation:
215 expevt = wf? EXPEVT_TLB_PROT_ST : EXPEVT_TLB_PROT_LD;
216 goto exception;
217
218 initial_write_exception:
219 expevt = EXPEVT_TLB_MOD;
220
221
222 exception:
223 if (flags & FLAG_NOEXCEPTIONS) {
224 *return_paddr = 0;
225 return 2;
226 }
227
228 sh_exception(cpu, expevt, 0, vaddr);
229
230 return 0;
231 }
232
233
234 /*
235 * sh_translate_v2p():
236 *
237 * Return values:
238 *
239 * 0 No access to the virtual address.
240 * 1 return_paddr contains the physical address, the page is
241 * available as read-only.
242 * 2 Same as 1, but the page is available as read/write.
243 */
244 int sh_translate_v2p(struct cpu *cpu, uint64_t vaddr, uint64_t *return_paddr,
245 int flags)
246 {
247 int user = cpu->cd.sh.sr & SH_SR_MD? 0 : 1;
248
249 vaddr = (uint32_t)vaddr;
250
251 /* U0/P0: Userspace addresses, or P3: Kernel virtual memory. */
252 if (!(vaddr & 0x80000000) ||
253 (vaddr >= 0xc0000000 && vaddr < 0xe0000000)) {
254 /* Address translation turned off? */
255 if (!(cpu->cd.sh.mmucr & SH4_MMUCR_AT)) {
256 /* Then return raw physical address: */
257 *return_paddr = vaddr & 0x1fffffff;
258 return 2;
259 }
260
261 /* Perform translation via the MMU: */
262 return translate_via_mmu(cpu, vaddr, return_paddr, flags);
263 }
264
265 /* Store queue region: */
266 if (vaddr >= 0xe0000000 && vaddr < 0xe4000000) {
267 /* Note/TODO: Take SH4_MMUCR_SQMD into account. */
268 *return_paddr = vaddr;
269 return 2;
270 }
271
272 if (user) {
273 if (flags & FLAG_NOEXCEPTIONS) {
274 *return_paddr = 0;
275 return 2;
276 }
277
278 fatal("Userspace tried to access non-user space memory."
279 " TODO: cause exception! (vaddr=0x%08"PRIx32"\n",
280 (uint32_t) vaddr);
281 exit(1);
282 }
283
284 /* P1,P2: Direct-mapped physical memory. */
285 if (vaddr >= 0x80000000 && vaddr < 0xc0000000) {
286 *return_paddr = vaddr & 0x1fffffff;
287 return 2;
288 }
289
290 if (flags & FLAG_INSTR) {
291 fatal("TODO: instr at 0x%08"PRIx32"\n", (uint32_t)vaddr);
292 exit(1);
293 }
294
295 /* P4: Special registers mapped at 0xf0000000 .. 0xffffffff: */
296 if ((vaddr & 0xf0000000) == 0xf0000000) {
297 *return_paddr = vaddr;
298 return 2;
299 }
300
301 if (flags & FLAG_NOEXCEPTIONS) {
302 *return_paddr = 0;
303 return 2;
304 }
305
306 /* TODO */
307 fatal("Unimplemented SH vaddr 0x%08"PRIx32"\n", (uint32_t)vaddr);
308 exit(1);
309 }
310

  ViewVC Help
Powered by ViewVC 1.1.26