memory_arm.cc Source File

Back to the index.

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

Generated on Tue Mar 24 2020 14:04:48 for GXemul by doxygen 1.8.17