/[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 26 - (hide annotations)
Mon Oct 8 16:20:10 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 8065 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 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 26 * $Id: memory_arm.c,v 1.35 2006/06/24 21:47:23 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     uint32_t ofs;
140     cpu->cd.arm.translation_table = memory_paddr_to_hostaddr(
141     cpu->mem, cpu->cd.arm.ttb & 0x0fffffff, 0);
142     if (cpu->cd.arm.translation_table != NULL) {
143     ofs = cpu->cd.arm.ttb & ((1 << BITS_PER_MEMBLOCK) - 1);
144     cpu->cd.arm.translation_table += ofs;
145     }
146     cpu->cd.arm.last_ttb = cpu->cd.arm.ttb;
147 dpavlin 14 }
148    
149 dpavlin 18 if (cpu->cd.arm.translation_table != NULL) {
150     d = *(uint32_t *)(cpu->cd.arm.translation_table + addr);
151     #ifdef HOST_LITTLE_ENDIAN
152     if (cpu->byte_order == EMUL_BIG_ENDIAN)
153     #else
154     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
155     #endif
156     d = ((d & 0xff) << 24) | ((d & 0xff00) << 8) |
157     ((d & 0xff0000) >> 8) | ((d & 0xff000000) >> 24);
158     }
159 dpavlin 14
160     /* Get the domain from the descriptor, and the Domain Access Value: */
161     domain = (d >> 5) & 15;
162     dav = (cpu->cd.arm.dacr >> (domain * 2)) & 3;
163    
164     switch (d & 3) {
165    
166 dpavlin 18 case 0: domain = 0;
167 dpavlin 14 fs = FAULT_TRANS_S;
168     goto exception_return;
169    
170     case 1: /* Course Pagetable: */
171 dpavlin 18 if (dav == 0) {
172     fs = FAULT_DOMAIN_P;
173     goto exception_return;
174     }
175 dpavlin 14 ptba = d & 0xfffffc00;
176     addr = ptba + ((vaddr & 0x000ff000) >> 10);
177 dpavlin 18
178     q = memory_paddr_to_hostaddr(cpu->mem, addr & 0x0fffffff, 0);
179     if (q == NULL) {
180     printf("arm memory blah blah adfh asfg asdgasdg\n");
181 dpavlin 14 exit(1);
182     }
183 dpavlin 18 d2 = *(uint32_t *)(q + (addr & ((1 << BITS_PER_MEMBLOCK) - 1)));
184     #ifdef HOST_LITTLE_ENDIAN
185     if (cpu->byte_order == EMUL_BIG_ENDIAN)
186     #else
187 dpavlin 14 if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
188 dpavlin 18 #endif
189     d2 = ((d2 & 0xff) << 24) | ((d2 & 0xff00) << 8) |
190     ((d2 & 0xff0000) >> 8) | ((d2 & 0xff000000) >> 24);
191 dpavlin 14
192     switch (d2 & 3) {
193     case 0: fs = FAULT_TRANS_P;
194     goto exception_return;
195     case 1: /* 16KB page: */
196     ap = (d2 >> 4) & 255;
197     switch (vaddr & 0x0000c000) {
198     case 0x4000: ap >>= 2; break;
199     case 0x8000: ap >>= 4; break;
200     case 0xc000: ap >>= 6; break;
201     }
202     ap &= 3;
203 dpavlin 26 *return_paddr = (d2 & 0xffff0000)|(vaddr & 0x0000ffff);
204 dpavlin 14 break;
205 dpavlin 22 case 3: if (cpu->cd.arm.cpu_type.flags & ARM_XSCALE) {
206     /* 4KB page (Xscale) */
207     subpage = 0;
208     } else {
209     /* 1KB page */
210     subpage = 1;
211     ap = (d2 >> 4) & 3;
212 dpavlin 26 *return_paddr = (d2 & 0xfffffc00) |
213 dpavlin 22 (vaddr & 0x000003ff);
214     break;
215 dpavlin 20 }
216 dpavlin 22 /* NOTE: Fall-through for XScale! */
217 dpavlin 14 case 2: /* 4KB page: */
218     ap3 = (d2 >> 10) & 3;
219     ap2 = (d2 >> 8) & 3;
220     ap1 = (d2 >> 6) & 3;
221     ap0 = (d2 >> 4) & 3;
222     switch (vaddr & 0x00000c00) {
223     case 0x000: ap = ap0; break;
224     case 0x400: ap = ap1; break;
225     case 0x800: ap = ap2; break;
226     default: ap = ap3;
227     }
228 dpavlin 22 /* NOTE: Ugly hack for XScale: */
229     if ((d2 & 3) == 3) {
230     /* Treated as 4KB page: */
231 dpavlin 20 ap = ap0;
232 dpavlin 22 } else {
233     if (ap0 != ap1 || ap0 != ap2 || ap0 != ap3)
234     subpage = 1;
235     }
236 dpavlin 26 *return_paddr = (d2 & 0xfffff000)|(vaddr & 0x00000fff);
237 dpavlin 14 break;
238     }
239     access = arm_check_access(cpu, ap, dav, user);
240     if (access > writeflag)
241 dpavlin 18 return access | (subpage? MEMORY_NOT_FULL_PAGE : 0);
242 dpavlin 14 fs = FAULT_PERM_P;
243     goto exception_return;
244    
245     case 2: /* Section descriptor: */
246     if (dav == 0) {
247     fs = FAULT_DOMAIN_S;
248     goto exception_return;
249     }
250 dpavlin 26 *return_paddr = (d & 0xfff00000) | (vaddr & 0x000fffff);
251 dpavlin 14 ap = (d >> 10) & 3;
252     access = arm_check_access(cpu, ap, dav, user);
253     if (access > writeflag)
254     return access;
255     fs = FAULT_PERM_S;
256     goto exception_return;
257    
258     default:fatal("TODO: descriptor for vaddr 0x%08x: 0x%08x ("
259     "unimplemented type %i)\n", vaddr, d, d&3);
260     exit(1);
261     }
262    
263     exception_return:
264     if (no_exceptions)
265     return 0;
266    
267     if (!quiet_mode) {
268     fatal("{ arm memory fault: vaddr=0x%08x domain=%i dav=%i ap=%i "
269     "access=%i user=%i", (int)vaddr, domain, dav, ap,
270     access, user);
271 dpavlin 22 fatal(" d=0x%08x d2=0x%08x pc=0x%08x }\n", d, d2, (int)cpu->pc);
272 dpavlin 14 }
273    
274     if (instr)
275     arm_exception(cpu, ARM_EXCEPTION_PREF_ABT);
276     else {
277     cpu->cd.arm.far = vaddr;
278     cpu->cd.arm.fsr = (domain << 4) | fs;
279     arm_exception(cpu, ARM_EXCEPTION_DATA_ABT);
280     }
281    
282     return 0;
283     }
284    

  ViewVC Help
Powered by ViewVC 1.1.26