/[gxemul]/trunk/src/cpus/memory_arm.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_arm.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: 7856 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 24 * Copyright (C) 2005-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_arm.c,v 1.36 2006/07/14 16:33:28 debug Exp $
29 dpavlin 14 *
30     *
31 dpavlin 18 * TODO/NOTE: The B and/or C bits could also cause the return value to
32     * be MEMORY_NOT_FULL_PAGE, to make sure it doesn't get entered into the
33     * translation arrays. TODO: Find out if this is a good thing to do.
34 dpavlin 14 */
35    
36     #include <stdio.h>
37     #include <stdlib.h>
38     #include <string.h>
39    
40 dpavlin 22 #include "arm_cpu_types.h"
41 dpavlin 14 #include "cpu.h"
42     #include "memory.h"
43     #include "misc.h"
44    
45     #include "armreg.h"
46    
47     extern int quiet_mode;
48    
49    
50     /*
51 dpavlin 26 * arm_translate_v2p():
52 dpavlin 18 *
53 dpavlin 26 * Address translation with the MMU disabled. (Just treat the virtual address
54     * as a physical address.)
55 dpavlin 18 */
56 dpavlin 26 int arm_translate_v2p(struct cpu *cpu, uint64_t vaddr64,
57     uint64_t *return_paddr, int flags)
58 dpavlin 18 {
59 dpavlin 26 *return_paddr = vaddr64 & 0xffffffff;
60    
61 dpavlin 18 return 2;
62     }
63    
64    
65     /*
66 dpavlin 14 * arm_check_access():
67     *
68     * Helper function. Returns 0 for no access, 1 for read-only, and 2 for
69     * read/write.
70     */
71     static int arm_check_access(struct cpu *cpu, int ap, int dav, int user)
72     {
73     int s, r;
74    
75     switch (dav) {
76     case 0: /* No access at all. */
77     return 0;
78     case 1: /* Normal access check. */
79     break;
80     case 2: fatal("arm_check_access(): 1 shouldn't be used\n");
81     exit(1);
82     case 3: /* Anything is allowed. */
83     return 2;
84     }
85    
86     switch (ap) {
87     case 0: s = (cpu->cd.arm.control & ARM_CONTROL_S)? 1 : 0;
88     r = (cpu->cd.arm.control & ARM_CONTROL_R)? 2 : 0;
89     switch (s + r) {
90     case 0: return 0;
91     case 1: return user? 0 : 1;
92     case 2: return 1;
93     }
94     fatal("arm_check_access: UNPREDICTABLE s+r value!\n");
95     return 0;
96     case 1: return user? 0 : 2;
97     case 2: return user? 1 : 2;
98     }
99    
100     /* "case 3": */
101     return 2;
102     }
103    
104    
105     /*
106 dpavlin 26 * arm_translate_v2p_mmu():
107 dpavlin 14 *
108     * Don't call this function is userland_emul is non-NULL, or cpu is NULL.
109     *
110     * Return values:
111     * 0 Failure
112     * 1 Success, the page is readable only
113     * 2 Success, the page is read/write
114 dpavlin 18 *
115     * If this is a 1KB page access, then the return value is ORed with
116     * MEMORY_NOT_FULL_PAGE.
117 dpavlin 14 */
118 dpavlin 26 int arm_translate_v2p_mmu(struct cpu *cpu, uint64_t vaddr64,
119     uint64_t *return_paddr, int flags)
120 dpavlin 14 {
121 dpavlin 18 unsigned char *q;
122     uint32_t addr, d=0, d2 = (uint32_t)(int32_t)-1, ptba, vaddr = vaddr64;
123 dpavlin 14 int instr = flags & FLAG_INSTR;
124     int writeflag = (flags & FLAG_WRITEFLAG)? 1 : 0;
125     int useraccess = flags & MEMORY_USER_ACCESS;
126     int no_exceptions = flags & FLAG_NOEXCEPTIONS;
127     int user = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32;
128     int domain, dav, ap0,ap1,ap2,ap3, ap = 0, access = 0;
129     int fs = 2; /* fault status (2 = terminal exception) */
130 dpavlin 18 int subpage = 0;
131 dpavlin 14
132     if (useraccess)
133     user = 1;
134    
135 dpavlin 18 addr = ((vaddr & 0xfff00000ULL) >> 18);
136    
137     if (cpu->cd.arm.translation_table == NULL ||
138     cpu->cd.arm.ttb != cpu->cd.arm.last_ttb) {
139     cpu->cd.arm.translation_table = memory_paddr_to_hostaddr(
140     cpu->mem, cpu->cd.arm.ttb & 0x0fffffff, 0);
141     cpu->cd.arm.last_ttb = cpu->cd.arm.ttb;
142 dpavlin 14 }
143    
144 dpavlin 18 if (cpu->cd.arm.translation_table != NULL) {
145     d = *(uint32_t *)(cpu->cd.arm.translation_table + addr);
146     #ifdef HOST_LITTLE_ENDIAN
147     if (cpu->byte_order == EMUL_BIG_ENDIAN)
148     #else
149     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
150     #endif
151     d = ((d & 0xff) << 24) | ((d & 0xff00) << 8) |
152     ((d & 0xff0000) >> 8) | ((d & 0xff000000) >> 24);
153     }
154 dpavlin 14
155     /* Get the domain from the descriptor, and the Domain Access Value: */
156     domain = (d >> 5) & 15;
157     dav = (cpu->cd.arm.dacr >> (domain * 2)) & 3;
158    
159     switch (d & 3) {
160    
161 dpavlin 18 case 0: domain = 0;
162 dpavlin 14 fs = FAULT_TRANS_S;
163     goto exception_return;
164    
165     case 1: /* Course Pagetable: */
166 dpavlin 18 if (dav == 0) {
167     fs = FAULT_DOMAIN_P;
168     goto exception_return;
169     }
170 dpavlin 14 ptba = d & 0xfffffc00;
171     addr = ptba + ((vaddr & 0x000ff000) >> 10);
172 dpavlin 18
173     q = memory_paddr_to_hostaddr(cpu->mem, addr & 0x0fffffff, 0);
174     if (q == NULL) {
175     printf("arm memory blah blah adfh asfg asdgasdg\n");
176 dpavlin 14 exit(1);
177     }
178 dpavlin 28 d2 = *(uint32_t *)(q);
179 dpavlin 18 #ifdef HOST_LITTLE_ENDIAN
180     if (cpu->byte_order == EMUL_BIG_ENDIAN)
181     #else
182 dpavlin 14 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
183 dpavlin 18 #endif
184     d2 = ((d2 & 0xff) << 24) | ((d2 & 0xff00) << 8) |
185     ((d2 & 0xff0000) >> 8) | ((d2 & 0xff000000) >> 24);
186 dpavlin 14
187     switch (d2 & 3) {
188     case 0: fs = FAULT_TRANS_P;
189     goto exception_return;
190     case 1: /* 16KB page: */
191     ap = (d2 >> 4) & 255;
192     switch (vaddr & 0x0000c000) {
193     case 0x4000: ap >>= 2; break;
194     case 0x8000: ap >>= 4; break;
195     case 0xc000: ap >>= 6; break;
196     }
197     ap &= 3;
198 dpavlin 26 *return_paddr = (d2 & 0xffff0000)|(vaddr & 0x0000ffff);
199 dpavlin 14 break;
200 dpavlin 22 case 3: if (cpu->cd.arm.cpu_type.flags & ARM_XSCALE) {
201     /* 4KB page (Xscale) */
202     subpage = 0;
203     } else {
204     /* 1KB page */
205     subpage = 1;
206     ap = (d2 >> 4) & 3;
207 dpavlin 26 *return_paddr = (d2 & 0xfffffc00) |
208 dpavlin 22 (vaddr & 0x000003ff);
209     break;
210 dpavlin 20 }
211 dpavlin 22 /* NOTE: Fall-through for XScale! */
212 dpavlin 14 case 2: /* 4KB page: */
213     ap3 = (d2 >> 10) & 3;
214     ap2 = (d2 >> 8) & 3;
215     ap1 = (d2 >> 6) & 3;
216     ap0 = (d2 >> 4) & 3;
217     switch (vaddr & 0x00000c00) {
218     case 0x000: ap = ap0; break;
219     case 0x400: ap = ap1; break;
220     case 0x800: ap = ap2; break;
221     default: ap = ap3;
222     }
223 dpavlin 22 /* NOTE: Ugly hack for XScale: */
224     if ((d2 & 3) == 3) {
225     /* Treated as 4KB page: */
226 dpavlin 20 ap = ap0;
227 dpavlin 22 } else {
228     if (ap0 != ap1 || ap0 != ap2 || ap0 != ap3)
229     subpage = 1;
230     }
231 dpavlin 26 *return_paddr = (d2 & 0xfffff000)|(vaddr & 0x00000fff);
232 dpavlin 14 break;
233     }
234     access = arm_check_access(cpu, ap, dav, user);
235     if (access > writeflag)
236 dpavlin 18 return access | (subpage? MEMORY_NOT_FULL_PAGE : 0);
237 dpavlin 14 fs = FAULT_PERM_P;
238     goto exception_return;
239    
240     case 2: /* Section descriptor: */
241     if (dav == 0) {
242     fs = FAULT_DOMAIN_S;
243     goto exception_return;
244     }
245 dpavlin 26 *return_paddr = (d & 0xfff00000) | (vaddr & 0x000fffff);
246 dpavlin 14 ap = (d >> 10) & 3;
247     access = arm_check_access(cpu, ap, dav, user);
248     if (access > writeflag)
249     return access;
250     fs = FAULT_PERM_S;
251     goto exception_return;
252    
253     default:fatal("TODO: descriptor for vaddr 0x%08x: 0x%08x ("
254     "unimplemented type %i)\n", vaddr, d, d&3);
255     exit(1);
256     }
257    
258     exception_return:
259     if (no_exceptions)
260     return 0;
261    
262     if (!quiet_mode) {
263     fatal("{ arm memory fault: vaddr=0x%08x domain=%i dav=%i ap=%i "
264     "access=%i user=%i", (int)vaddr, domain, dav, ap,
265     access, user);
266 dpavlin 22 fatal(" d=0x%08x d2=0x%08x pc=0x%08x }\n", d, d2, (int)cpu->pc);
267 dpavlin 14 }
268    
269     if (instr)
270     arm_exception(cpu, ARM_EXCEPTION_PREF_ABT);
271     else {
272     cpu->cd.arm.far = vaddr;
273     cpu->cd.arm.fsr = (domain << 4) | fs;
274     arm_exception(cpu, ARM_EXCEPTION_DATA_ABT);
275     }
276    
277     return 0;
278     }
279    

  ViewVC Help
Powered by ViewVC 1.1.26