/[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 18 - (hide annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 7664 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26