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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (hide annotations)
Mon Oct 8 16:21:34 2007 UTC (13 years, 3 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 dpavlin 30 /*
2 dpavlin 34 * Copyright (C) 2006-2007 Anders Gavare. All rights reserved.
3 dpavlin 30 *
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 36 * $Id: memory_sh.c,v 1.16 2007/03/08 10:02:32 debug Exp $
29 dpavlin 30 */
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 dpavlin 32 #include "sh4_exception.h"
41     #include "sh4_mmu.h"
42 dpavlin 30
43 dpavlin 32
44 dpavlin 30 /*
45 dpavlin 32 * 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 dpavlin 30 */
57 dpavlin 32 static int translate_via_mmu(struct cpu *cpu, uint32_t vaddr,
58 dpavlin 30 uint64_t *return_paddr, int flags)
59     {
60 dpavlin 32 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 dpavlin 30
69 dpavlin 32 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 dpavlin 36 if (urc >= SH_N_UTLB_ENTRIES || (urb > 0 && urc == urb))
89 dpavlin 32 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 dpavlin 36 /* Matching address found! Let's see whether it is
145     readable/writable, etc.: */
146     d = lo & SH4_PTEL_D? 1 : 0;
147 dpavlin 32 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 dpavlin 34
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 dpavlin 32 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 dpavlin 36 return 1 + d;
194 dpavlin 32 }
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 dpavlin 36 return 1 + d;
207 dpavlin 32 }
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 dpavlin 30 }
232    
233 dpavlin 32
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