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

Diff of /trunk/src/cpus/memory_arm.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 14 by dpavlin, Mon Oct 8 16:18:51 2007 UTC revision 26 by dpavlin, Mon Oct 8 16:20:10 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2005-2006  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: memory_arm.c,v 1.23 2005/10/07 15:19:48 debug Exp $   *  $Id: memory_arm.c,v 1.35 2006/06/24 21:47:23 debug Exp $
29   *   *
30   *   *
31   *  TODO/NOTE: There are probably two solutions to the subpage access   *  TODO/NOTE:  The B and/or C bits could also cause the return value to
32   *  permission problem:   *  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.
  *  a) the obvious (almost trivial) solution is to decrease the native page  
  *     size from 4 KB to 1 KB. That would ruin the rest of the translation  
  *     system though. (It would be infeasible to hold the entire address  
  *     space in 1-level tables.)  
  *  
  *  b) to return something else than just 0, 1, or 2 from arm_memory_rw().  
  *     Perhaps |4, which would indicate that the vaddr => paddr conversion  
  *     was done, but that it should not be entered into the cache. This could  
  *     also be used in combination with the B and C bits (which are currently  
  *     ignored).  
  *  
  *  b would probably be the best solution.  
34   */   */
35    
36  #include <stdio.h>  #include <stdio.h>
37  #include <stdlib.h>  #include <stdlib.h>
38  #include <string.h>  #include <string.h>
39    
40    #include "arm_cpu_types.h"
41  #include "cpu.h"  #include "cpu.h"
42  #include "memory.h"  #include "memory.h"
43  #include "misc.h"  #include "misc.h"
# Line 59  extern int quiet_mode; Line 48  extern int quiet_mode;
48    
49    
50  /*  /*
51     *  arm_translate_v2p():
52     *
53     *  Address translation with the MMU disabled. (Just treat the virtual address
54     *  as a physical address.)
55     */
56    int arm_translate_v2p(struct cpu *cpu, uint64_t vaddr64,
57            uint64_t *return_paddr, int flags)
58    {
59            *return_paddr = vaddr64 & 0xffffffff;
60    
61            return 2;
62    }
63    
64    
65    /*
66   *  arm_check_access():   *  arm_check_access():
67   *   *
68   *  Helper function.  Returns 0 for no access, 1 for read-only, and 2 for   *  Helper function.  Returns 0 for no access, 1 for read-only, and 2 for
# Line 99  static int arm_check_access(struct cpu * Line 103  static int arm_check_access(struct cpu *
103    
104    
105  /*  /*
106   *  arm_translate_address():   *  arm_translate_v2p_mmu():
107   *   *
108   *  Don't call this function is userland_emul is non-NULL, or cpu is NULL.   *  Don't call this function is userland_emul is non-NULL, or cpu is NULL.
109   *   *
# Line 107  static int arm_check_access(struct cpu * Line 111  static int arm_check_access(struct cpu *
111   *      0  Failure   *      0  Failure
112   *      1  Success, the page is readable only   *      1  Success, the page is readable only
113   *      2  Success, the page is read/write   *      2  Success, the page is read/write
114     *
115     *  If this is a 1KB page access, then the return value is ORed with
116     *  MEMORY_NOT_FULL_PAGE.
117   */   */
118  int arm_translate_address(struct cpu *cpu, uint64_t vaddr64,  int arm_translate_v2p_mmu(struct cpu *cpu, uint64_t vaddr64,
119          uint64_t *return_addr, int flags)          uint64_t *return_paddr, int flags)
120  {  {
121          unsigned char descr[4];          unsigned char *q;
122          uint32_t addr, d, d2 = (uint32_t)(int32_t)-1, ptba, vaddr = vaddr64;          uint32_t addr, d=0, d2 = (uint32_t)(int32_t)-1, ptba, vaddr = vaddr64;
         int d2_in_use = 0, d_in_use = 1;  
123          int instr = flags & FLAG_INSTR;          int instr = flags & FLAG_INSTR;
124          int writeflag = (flags & FLAG_WRITEFLAG)? 1 : 0;          int writeflag = (flags & FLAG_WRITEFLAG)? 1 : 0;
125          int useraccess = flags & MEMORY_USER_ACCESS;          int useraccess = flags & MEMORY_USER_ACCESS;
# Line 121  int arm_translate_address(struct cpu *cp Line 127  int arm_translate_address(struct cpu *cp
127          int user = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32;          int user = (cpu->cd.arm.cpsr & ARM_FLAG_MODE) == ARM_MODE_USR32;
128          int domain, dav, ap0,ap1,ap2,ap3, ap = 0, access = 0;          int domain, dav, ap0,ap1,ap2,ap3, ap = 0, access = 0;
129          int fs = 2;             /*  fault status (2 = terminal exception)  */          int fs = 2;             /*  fault status (2 = terminal exception)  */
130            int subpage = 0;
         if (!(cpu->cd.arm.control & ARM_CONTROL_MMU)) {  
                 *return_addr = vaddr;  
                 return 2;  
         }  
131    
132          if (useraccess)          if (useraccess)
133                  user = 1;                  user = 1;
134    
135          addr = cpu->cd.arm.ttb + ((vaddr & 0xfff00000ULL) >> 18);          addr = ((vaddr & 0xfff00000ULL) >> 18);
136          if (!cpu->memory_rw(cpu, cpu->mem, addr, &descr[0],  
137              sizeof(descr), MEM_READ, PHYSICAL | NO_EXCEPTIONS)) {          if (cpu->cd.arm.translation_table == NULL ||
138                  fatal("arm_translate_address(): huh?\n");              cpu->cd.arm.ttb != cpu->cd.arm.last_ttb) {
139                  exit(1);                  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          }          }
         if (cpu->byte_order == EMUL_LITTLE_ENDIAN)  
                 d = descr[0] + (descr[1] << 8) + (descr[2] << 16)  
                     + (descr[3] << 24);  
         else  
                 d = descr[3] + (descr[2] << 8) + (descr[1] << 16)  
                     + (descr[0] << 24);  
148    
149          /*  fatal("vaddr=0x%08x ttb=0x%08x addr=0x%08x d=0x%08x\n",          if (cpu->cd.arm.translation_table != NULL) {
150              vaddr, cpu->cd.arm.ttb, addr, d);  */                  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    
160          /*  Get the domain from the descriptor, and the Domain Access Value:  */          /*  Get the domain from the descriptor, and the Domain Access Value:  */
161          domain = (d >> 5) & 15;          domain = (d >> 5) & 15;
# Line 152  int arm_translate_address(struct cpu *cp Line 163  int arm_translate_address(struct cpu *cp
163    
164          switch (d & 3) {          switch (d & 3) {
165    
166          case 0: d_in_use = 0;          case 0: domain = 0;
                 domain = 0;  
167                  fs = FAULT_TRANS_S;                  fs = FAULT_TRANS_S;
168                  goto exception_return;                  goto exception_return;
169    
170          case 1: /*  Course Pagetable:  */          case 1: /*  Course Pagetable:  */
171                    if (dav == 0) {
172                            fs = FAULT_DOMAIN_P;
173                            goto exception_return;
174                    }
175                  ptba = d & 0xfffffc00;                  ptba = d & 0xfffffc00;
176                  addr = ptba + ((vaddr & 0x000ff000) >> 10);                  addr = ptba + ((vaddr & 0x000ff000) >> 10);
177                  if (!cpu->memory_rw(cpu, cpu->mem, addr, &descr[0],  
178                      sizeof(descr), MEM_READ, PHYSICAL | NO_EXCEPTIONS)) {                  q = memory_paddr_to_hostaddr(cpu->mem, addr & 0x0fffffff, 0);
179                          fatal("arm_translate_address(): huh 2?\n");                  if (q == NULL) {
180                            printf("arm memory blah blah adfh asfg asdgasdg\n");
181                          exit(1);                          exit(1);
182                  }                  }
183                    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                  if (cpu->byte_order == EMUL_LITTLE_ENDIAN)                  if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
188                          d2 = descr[0] + (descr[1] << 8) + (descr[2] << 16)  #endif
189                              + (descr[3] << 24);                          d2 = ((d2 & 0xff) << 24) | ((d2 & 0xff00) << 8) |
190                  else                               ((d2 & 0xff0000) >> 8) | ((d2 & 0xff000000) >> 24);
                         d2 = descr[3] + (descr[2] << 8) + (descr[1] << 16)  
                             + (descr[0] << 24);  
                 d2_in_use = 1;  
191    
192                  switch (d2 & 3) {                  switch (d2 & 3) {
193                  case 0: fs = FAULT_TRANS_P;                  case 0: fs = FAULT_TRANS_P;
# Line 184  int arm_translate_address(struct cpu *cp Line 200  int arm_translate_address(struct cpu *cp
200                          case 0xc000:    ap >>= 6; break;                          case 0xc000:    ap >>= 6; break;
201                          }                          }
202                          ap &= 3;                          ap &= 3;
203                          *return_addr = (d2 & 0xffff0000) | (vaddr & 0x0000ffff);                          *return_paddr = (d2 & 0xffff0000)|(vaddr & 0x0000ffff);
204                          break;                          break;
205                    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                                    *return_paddr = (d2 & 0xfffffc00) |
213                                        (vaddr & 0x000003ff);
214                                    break;
215                            }
216                            /*  NOTE: Fall-through for XScale!  */
217                  case 2: /*  4KB page:  */                  case 2: /*  4KB page:  */
218                          ap3 = (d2 >> 10) & 3;                          ap3 = (d2 >> 10) & 3;
219                          ap2 = (d2 >>  8) & 3;                          ap2 = (d2 >>  8) & 3;
# Line 197  int arm_translate_address(struct cpu *cp Line 225  int arm_translate_address(struct cpu *cp
225                          case 0x800: ap = ap2; break;                          case 0x800: ap = ap2; break;
226                          default:    ap = ap3;                          default:    ap = ap3;
227                          }                          }
228  #if 0                          /*  NOTE: Ugly hack for XScale:  */
229                          if ((ap0 != ap1 || ap0 != ap2 || ap0 != ap3) &&                          if ((d2 & 3) == 3) {
230                              !no_exceptions)                                  /*  Treated as 4KB page:  */
231                                  fatal("WARNING: vaddr = 0x%08x, small page, but"                                  ap = ap0;
232                                      " different access permissions for the sub"                          } else {
233                                      "pages! This is not really implemented "                                  if (ap0 != ap1 || ap0 != ap2 || ap0 != ap3)
234                                      "yet.\n", (int)vaddr);                                          subpage = 1;
235  #endif                          }
236                          *return_addr = (d2 & 0xfffff000) | (vaddr & 0x00000fff);                          *return_paddr = (d2 & 0xfffff000)|(vaddr & 0x00000fff);
                         break;  
                 case 3: /*  1KB page:  */  
                         fatal("WARNING: 1 KB page! Not implemented yet.\n");  
                         ap = (d2 >> 4) & 3;  
                         *return_addr = (d2 & 0xfffffc00) | (vaddr & 0x000003ff);  
237                          break;                          break;
238                  }                  }
                 if (dav == 0) {  
                         fs = FAULT_DOMAIN_P;  
                         goto exception_return;  
                 }  
239                  access = arm_check_access(cpu, ap, dav, user);                  access = arm_check_access(cpu, ap, dav, user);
240                  if (access > writeflag)                  if (access > writeflag)
241                          return access;                          return access | (subpage? MEMORY_NOT_FULL_PAGE : 0);
242                  fs = FAULT_PERM_P;                  fs = FAULT_PERM_P;
243                  goto exception_return;                  goto exception_return;
244    
245          case 2: /*  Section descriptor:  */          case 2: /*  Section descriptor:  */
                 *return_addr = (d & 0xfff00000) | (vaddr & 0x000fffff);  
246                  if (dav == 0) {                  if (dav == 0) {
247                          fs = FAULT_DOMAIN_S;                          fs = FAULT_DOMAIN_S;
248                          goto exception_return;                          goto exception_return;
249                  }                  }
250                    *return_paddr = (d & 0xfff00000) | (vaddr & 0x000fffff);
251                  ap = (d >> 10) & 3;                  ap = (d >> 10) & 3;
252                  access = arm_check_access(cpu, ap, dav, user);                  access = arm_check_access(cpu, ap, dav, user);
253                  if (access > writeflag)                  if (access > writeflag)
# Line 249  exception_return: Line 268  exception_return:
268                  fatal("{ arm memory fault: vaddr=0x%08x domain=%i dav=%i ap=%i "                  fatal("{ arm memory fault: vaddr=0x%08x domain=%i dav=%i ap=%i "
269                      "access=%i user=%i", (int)vaddr, domain, dav, ap,                      "access=%i user=%i", (int)vaddr, domain, dav, ap,
270                      access, user);                      access, user);
271                  if (d_in_use)                  fatal(" d=0x%08x d2=0x%08x pc=0x%08x }\n", d, d2, (int)cpu->pc);
                         fatal(" d=0x%08x", d);  
                 if (d2_in_use)  
                         fatal(" d2=0x%08x", d2);  
                 fatal(" }\n");  
272          }          }
273    
274          if (instr)          if (instr)

Legend:
Removed from v.14  
changed lines
  Added in v.26

  ViewVC Help
Powered by ViewVC 1.1.26