/[gxemul]/trunk/src/memory_rw.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/memory_rw.c

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

revision 30 by dpavlin, Mon Oct 8 16:20:40 2007 UTC revision 42 by dpavlin, Mon Oct 8 16:22:32 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2006  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2007  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_rw.c,v 1.95 2006/07/25 21:49:14 debug Exp $   *  $Id: memory_rw.c,v 1.107 2007/06/12 03:49:11 debug Exp $
29   *   *
30   *  Generic memory_rw(), with special hacks for specific CPU families.   *  Generic memory_rw(), with special hacks for specific CPU families.
31   *   *
# Line 33  Line 33 
33   *   *
34   *      MEMORY_RW should be mips_memory_rw   *      MEMORY_RW should be mips_memory_rw
35   *      MEM_MIPS should be defined   *      MEM_MIPS should be defined
36     *
37     *
38     *  TODO: Cleanup the "ok" variable usage!
39   */   */
40    
41    
# Line 71  int MEMORY_RW(struct cpu *cpu, struct me Line 74  int MEMORY_RW(struct cpu *cpu, struct me
74  #endif  #endif
75    
76  #ifndef MEM_USERLAND  #ifndef MEM_USERLAND
77          int ok = 1;          int ok = 2;
78  #endif  #endif
79          uint64_t paddr;          uint64_t paddr;
80          int cache, no_exceptions, offset;          int cache, no_exceptions, offset;
# Line 81  int MEMORY_RW(struct cpu *cpu, struct me Line 84  int MEMORY_RW(struct cpu *cpu, struct me
84          no_exceptions = misc_flags & NO_EXCEPTIONS;          no_exceptions = misc_flags & NO_EXCEPTIONS;
85          cache = misc_flags & CACHE_FLAGS_MASK;          cache = misc_flags & CACHE_FLAGS_MASK;
86    
 #ifdef MEM_X86  
         /*  Real-mode wrap-around:  */  
         if (REAL_MODE && !(misc_flags & PHYSICAL)) {  
                 if ((vaddr & 0xffff) + len > 0x10000) {  
                         /*  Do one byte at a time:  */  
                         int res = 0;  
                         size_t i;  
                         for (i=0; i<len; i++)  
                                 res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,  
                                     writeflag, misc_flags);  
                         return res;  
                 }  
         }  
   
         /*  Crossing a page boundary? Then do one byte at a time:  */  
         if ((vaddr & 0xfff) + len > 0x1000 && !(misc_flags & PHYSICAL)  
             && cpu->cd.x86.cr[0] & X86_CR0_PG) {  
                 /*  For WRITES: Read ALL BYTES FIRST and write them back!!!  
                     Then do a write of all the new bytes. This is to make sure  
                     than both pages around the boundary are writable so we don't  
                     do a partial write.  */  
                 int res = 0;  
                 size_t i;  
                 if (writeflag == MEM_WRITE) {  
                         unsigned char tmp;  
                         for (i=0; i<len; i++) {  
                                 res = MEMORY_RW(cpu, mem, vaddr+i, &tmp, 1,  
                                     MEM_READ, misc_flags);  
                                 if (!res)  
                                         return 0;  
                                 res = MEMORY_RW(cpu, mem, vaddr+i, &tmp, 1,  
                                     MEM_WRITE, misc_flags);  
                                 if (!res)  
                                         return 0;  
                         }  
                         for (i=0; i<len; i++) {  
                                 res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,  
                                     MEM_WRITE, misc_flags);  
                                 if (!res)  
                                         return 0;  
                         }  
                 } else {  
                         for (i=0; i<len; i++) {  
                                 /*  Do one byte at a time:  */  
                                 res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,  
                                     writeflag, misc_flags);  
                                 if (!res) {  
                                         if (cache == CACHE_INSTRUCTION) {  
                                                 fatal("FAILED instruction "  
                                                     "fetch across page boundar"  
                                                     "y: todo. vaddr=0x%08x\n",  
                                                     (int)vaddr);  
                                                 cpu->running = 0;  
                                         }  
                                         return 0;  
                                 }  
                         }  
                 }  
                 return res;  
         }  
 #endif  /*  X86  */  
   
87    
88  #ifdef MEM_USERLAND  #ifdef MEM_USERLAND
89  #ifdef MEM_ALPHA  #ifdef MEM_ALPHA
# Line 157  int MEMORY_RW(struct cpu *cpu, struct me Line 98  int MEMORY_RW(struct cpu *cpu, struct me
98                  ok = cpu->translate_v2p(cpu, vaddr, &paddr,                  ok = cpu->translate_v2p(cpu, vaddr, &paddr,
99                      (writeflag? FLAG_WRITEFLAG : 0) +                      (writeflag? FLAG_WRITEFLAG : 0) +
100                      (no_exceptions? FLAG_NOEXCEPTIONS : 0)                      (no_exceptions? FLAG_NOEXCEPTIONS : 0)
 #ifdef MEM_X86  
                     + (misc_flags & NO_SEGMENTATION)  
 #endif  
 #ifdef MEM_ARM  
101                      + (misc_flags & MEMORY_USER_ACCESS)                      + (misc_flags & MEMORY_USER_ACCESS)
 #endif  
102                      + (cache==CACHE_INSTRUCTION? FLAG_INSTR : 0));                      + (cache==CACHE_INSTRUCTION? FLAG_INSTR : 0));
103                  /*  If the translation caused an exception, or was invalid in  
104                      some way, we simply return without doing the memory                  /*
105                      access:  */                   *  If the translation caused an exception, or was invalid in
106                     *  some way, then simply return without doing the memory
107                     *  access:
108                     */
109                  if (!ok)                  if (!ok)
110                          return MEMORY_ACCESS_FAILED;                          return MEMORY_ACCESS_FAILED;
111          }          }
112    
   
 #ifdef MEM_X86  
         /*  DOS debugging :-)  */  
         if (!quiet_mode && !(misc_flags & PHYSICAL)) {  
                 if (paddr >= 0x400 && paddr <= 0x4ff)  
                         debug("{ PC BIOS DATA AREA: %s 0x%x }\n", writeflag ==  
                             MEM_WRITE? "writing to" : "reading from",  
                             (int)paddr);  
 #if 0  
                 if (paddr >= 0xf0000 && paddr <= 0xfffff)  
                         debug("{ BIOS ACCESS: %s 0x%x }\n",  
                             writeflag == MEM_WRITE? "writing to" :  
                             "reading from", (int)paddr);  
 #endif  
         }  
 #endif  
113  #endif  /*  !MEM_USERLAND  */  #endif  /*  !MEM_USERLAND  */
114    
115    
# Line 201  int MEMORY_RW(struct cpu *cpu, struct me Line 124  int MEMORY_RW(struct cpu *cpu, struct me
124                  uint64_t orig_paddr = paddr;                  uint64_t orig_paddr = paddr;
125                  int i, start, end, res;                  int i, start, end, res;
126    
127    #if 0
128    
129    TODO: The correct solution for this is to add RAM devices _around_ the
130    dangerous device. The solution below incurs a slowdown for _everything_,
131    not just the device in question.
132    
133                  /*                  /*
134                   *  Really really slow, but unfortunately necessary. This is                   *  Really really slow, but unfortunately necessary. This is
135                   *  to avoid the folowing scenario:                   *  to avoid the folowing scenario:
# Line 222  int MEMORY_RW(struct cpu *cpu, struct me Line 151  int MEMORY_RW(struct cpu *cpu, struct me
151                   *  TODO: Convert this into a quick (multi-level, 64-bit)                   *  TODO: Convert this into a quick (multi-level, 64-bit)
152                   *  address space lookup, to find dangerous pages.                   *  address space lookup, to find dangerous pages.
153                   */                   */
 #if 1  
154                  for (i=0; i<mem->n_mmapped_devices; i++)                  for (i=0; i<mem->n_mmapped_devices; i++)
155                          if (paddr >= (mem->dev_baseaddr[i] & ~offset_mask) &&                          if (paddr >= (mem->devices[i].baseaddr & ~offset_mask)&&
156                              paddr <= ((mem->dev_endaddr[i]-1) | offset_mask)) {                              paddr <= ((mem->devices[i].endaddr-1)|offset_mask)){
157                                  dyntrans_device_danger = 1;                                  dyntrans_device_danger = 1;
158                                  break;                                  break;
159                          }                          }
# Line 236  int MEMORY_RW(struct cpu *cpu, struct me Line 164  int MEMORY_RW(struct cpu *cpu, struct me
164    
165                  /*  Scan through all devices:  */                  /*  Scan through all devices:  */
166                  do {                  do {
167                          if (paddr >= mem->dev_baseaddr[i] &&                          if (paddr >= mem->devices[i].baseaddr &&
168                              paddr < mem->dev_endaddr[i]) {                              paddr < mem->devices[i].endaddr) {
169                                  /*  Found a device, let's access it:  */                                  /*  Found a device, let's access it:  */
170                                  mem->last_accessed_device = i;                                  mem->last_accessed_device = i;
171    
172                                  paddr -= mem->dev_baseaddr[i];                                  paddr -= mem->devices[i].baseaddr;
173                                  if (paddr + len > mem->dev_length[i])                                  if (paddr + len > mem->devices[i].length)
174                                          len = mem->dev_length[i] - paddr;                                          len = mem->devices[i].length - paddr;
175    
176                                  if (cpu->update_translation_table != NULL &&                                  if (cpu->update_translation_table != NULL &&
177                                      !(ok & MEMORY_NOT_FULL_PAGE) &&                                      !(ok & MEMORY_NOT_FULL_PAGE) &&
178                                      mem->dev_flags[i] & DM_DYNTRANS_OK) {                                      mem->devices[i].flags & DM_DYNTRANS_OK) {
179                                          int wf = writeflag == MEM_WRITE? 1 : 0;                                          int wf = writeflag == MEM_WRITE? 1 : 0;
180                                          unsigned char *host_addr;                                          unsigned char *host_addr;
181    
182                                          if (!(mem->dev_flags[i] &                                          if (!(mem->devices[i].flags &
183                                              DM_DYNTRANS_WRITE_OK))                                              DM_DYNTRANS_WRITE_OK))
184                                                  wf = 0;                                                  wf = 0;
185    
186                                          if (writeflag && wf) {                                          if (writeflag && wf) {
187                                                  if (paddr < mem->                                                  if (paddr < mem->devices[i].
188                                                      dev_dyntrans_write_low[i])                                                      dyntrans_write_low)
189                                                          mem->                                                          mem->devices[i].
190                                                          dev_dyntrans_write_low                                                          dyntrans_write_low =
191                                                              [i] = paddr &                                                              paddr &~offset_mask;
192                                                              ~offset_mask;                                                  if (paddr >= mem->devices[i].
193                                                  if (paddr >= mem->                                                      dyntrans_write_high)
194                                                      dev_dyntrans_write_high[i])                                                          mem->devices[i].
195                                                          mem->                                                          dyntrans_write_high =
196                                                          dev_dyntrans_write_high                                                              paddr | offset_mask;
                                                             [i] = paddr |  
                                                             offset_mask;  
197                                          }                                          }
198    
199                                          if (mem->dev_flags[i] &                                          if (mem->devices[i].flags &
200                                              DM_EMULATED_RAM) {                                              DM_EMULATED_RAM) {
201                                                  /*  MEM_WRITE to force the page                                                  /*  MEM_WRITE to force the page
202                                                      to be allocated, if it                                                      to be allocated, if it
203                                                      wasn't already  */                                                      wasn't already  */
204                                                  uint64_t *pp = (uint64_t *)                                                  uint64_t *pp = (uint64_t *)mem->
205                                                      mem->dev_dyntrans_data[i];                                                      devices[i].dyntrans_data;
206                                                  uint64_t p = orig_paddr - *pp;                                                  uint64_t p = orig_paddr - *pp;
207                                                  host_addr =                                                  host_addr =
208                                                      memory_paddr_to_hostaddr(                                                      memory_paddr_to_hostaddr(
209                                                      mem, p & ~offset_mask,                                                      mem, p & ~offset_mask,
210                                                      MEM_WRITE);                                                      MEM_WRITE);
211                                          } else {                                          } else {
212                                                  host_addr =                                                  host_addr = mem->devices[i].
213                                                      mem->dev_dyntrans_data[i] +                                                      dyntrans_data +
214                                                      (paddr & ~offset_mask);                                                      (paddr & ~offset_mask);
215                                          }                                          }
216    
# Line 294  int MEMORY_RW(struct cpu *cpu, struct me Line 220  int MEMORY_RW(struct cpu *cpu, struct me
220                                  }                                  }
221    
222                                  res = 0;                                  res = 0;
223                                  if (!no_exceptions || (mem->dev_flags[i] &                                  if (!no_exceptions || (mem->devices[i].flags &
224                                      DM_READS_HAVE_NO_SIDE_EFFECTS))                                      DM_READS_HAVE_NO_SIDE_EFFECTS))
225                                          res = mem->dev_f[i](cpu, mem, paddr,                                          res = mem->devices[i].f(cpu, mem, paddr,
226                                              data, len, writeflag,                                              data, len, writeflag,
227                                              mem->dev_extra[i]);                                              mem->devices[i].extra);
228    
229                                  if (res == 0)                                  if (res == 0)
230                                          res = -1;                                          res = -1;
231    
 #ifndef MEM_X86  
232                                  /*                                  /*
233                                   *  If accessing the memory mapped device                                   *  If accessing the memory mapped device
234                                   *  failed, then return with a DBE exception.                                   *  failed, then return with a DBE exception.
# Line 312  int MEMORY_RW(struct cpu *cpu, struct me Line 237  int MEMORY_RW(struct cpu *cpu, struct me
237                                          debug("%s device '%s' addr %08lx "                                          debug("%s device '%s' addr %08lx "
238                                              "failed\n", writeflag?                                              "failed\n", writeflag?
239                                              "writing to" : "reading from",                                              "writing to" : "reading from",
240                                              mem->dev_name[i], (long)paddr);                                              mem->devices[i].name, (long)paddr);
241  #ifdef MEM_MIPS  #ifdef MEM_MIPS
242                                          mips_cpu_exception(cpu, EXCEPTION_DBE,                                          mips_cpu_exception(cpu,
243                                                cache == CACHE_INSTRUCTION?
244                                                EXCEPTION_IBE : EXCEPTION_DBE,
245                                              0, vaddr, 0, 0, 0, 0);                                              0, vaddr, 0, 0, 0, 0);
246  #endif  #endif
247                                          return MEMORY_ACCESS_FAILED;                                          return MEMORY_ACCESS_FAILED;
248                                  }                                  }
 #endif  
249                                  goto do_return_ok;                                  goto do_return_ok;
250                          }                          }
251    
252                          if (paddr < mem->dev_baseaddr[i])                          if (paddr < mem->devices[i].baseaddr)
253                                  end = i - 1;                                  end = i - 1;
254                          if (paddr >= mem->dev_endaddr[i])                          if (paddr >= mem->devices[i].endaddr)
255                                  start = i + 1;                                  start = i + 1;
256                          i = (start + end) >> 1;                          i = (start + end) >> 1;
257                  } while (start <= end);                  } while (start <= end);
# Line 370  int MEMORY_RW(struct cpu *cpu, struct me Line 296  int MEMORY_RW(struct cpu *cpu, struct me
296                  } else                  } else
297  #endif /* MIPS */  #endif /* MIPS */
298                  {                  {
299                          if (paddr >= mem->physical_max) {                          if (paddr >= mem->physical_max && !no_exceptions)
300                                  uint64_t offset, old_pc = cpu->pc;                                  memory_warn_about_unimplemented_addr
301                                  char *symbol;                                      (cpu, mem, writeflag, paddr, data, len);
   
                                 /*  This allows for example OS kernels to probe  
                                     memory a few KBs past the end of memory,  
                                     without giving too many warnings.  */  
                                 if (!quiet_mode && !no_exceptions && paddr >=  
                                     mem->physical_max + 0x40000) {  
                                         fatal("[ memory_rw(): writeflag=%i ",  
                                             writeflag);  
                                         if (writeflag) {  
                                                 unsigned int i;  
                                                 debug("data={", writeflag);  
                                                 if (len > 16) {  
                                                         int start2 = len-16;  
                                                         for (i=0; i<16; i++)  
                                                                 debug("%s%02x",  
                                                                     i?",":"",  
                                                                     data[i]);  
                                                         debug(" .. ");  
                                                         if (start2 < 16)  
                                                                 start2 = 16;  
                                                         for (i=start2; i<len;  
                                                             i++)  
                                                                 debug("%s%02x",  
                                                                     i?",":"",  
                                                                     data[i]);  
                                                 } else  
                                                         for (i=0; i<len; i++)  
                                                                 debug("%s%02x",  
                                                                     i?",":"",  
                                                                     data[i]);  
                                                 debug("}");  
                                         }  
   
                                         fatal(" paddr=0x%llx >= physical_max"  
                                             "; pc=", (long long)paddr);  
                                         if (cpu->is_32bit)  
                                                 fatal("0x%08x",(int)old_pc);  
                                         else  
                                                 fatal("0x%016llx",  
                                                     (long long)old_pc);  
                                         symbol = get_symbol_name(  
                                             &cpu->machine->symbol_context,  
                                             old_pc, &offset);  
                                         fatal(" <%s> ]\n",  
                                             symbol? symbol : " no symbol ");  
                                 }  
                         }  
302    
303                          if (writeflag == MEM_READ) {                          if (writeflag == MEM_READ) {
 #ifdef MEM_X86  
                                 /*  Reading non-existant memory on x86:  */  
                                 memset(data, 0xff, len);  
 #else  
304                                  /*  Return all zeroes? (Or 0xff? TODO)  */                                  /*  Return all zeroes? (Or 0xff? TODO)  */
305                                  memset(data, 0, len);                                  memset(data, 0, len);
 #endif  
306    
307    #if 0
308    /*
309     *  NOTE: This code prevents a PROM image from a real 5000/200 from booting.
310     *  I think I introduced it because it was how some guest OS (NetBSD?) detected
311     *  the amount of RAM on some machine.
312     *
313     *  TODO: Figure out if it is not needed anymore, and remove it completely.
314     */
315  #ifdef MEM_MIPS  #ifdef MEM_MIPS
316                                  /*                                  /*
317                                   *  For real data/instruction accesses, cause                                   *  For real data/instruction accesses, cause
318                                   *  an exceptions on an illegal read:                                   *  an exceptions on an illegal read:
319                                   */                                   */
320                                  if (cache != CACHE_NONE && cpu->machine->                                  if (cache != CACHE_NONE && !no_exceptions &&
321                                      dbe_on_nonexistant_memaccess &&                                      paddr >= mem->physical_max &&
322                                      !no_exceptions) {                                      paddr < mem->physical_max+1048576) {
323                                          if (paddr >= mem->physical_max &&                                          mips_cpu_exception(cpu,
324                                              paddr < mem->physical_max+1048576)                                              EXCEPTION_DBE, 0, vaddr, 0,
325                                                  mips_cpu_exception(cpu,                                              0, 0, 0);
                                                     EXCEPTION_DBE, 0, vaddr, 0,  
                                                     0, 0, 0);  
326                                  }                                  }
327  #endif  /*  MEM_MIPS  */  #endif  /*  MEM_MIPS  */
328    #endif
329                          }                          }
330    
331                          /*  Hm? Shouldn't there be a DBE exception for                          /*  Hm? Shouldn't there be a DBE exception for
# Line 484  int MEMORY_RW(struct cpu *cpu, struct me Line 365  int MEMORY_RW(struct cpu *cpu, struct me
365              && (cpu->cd.mips.cpu_type.mmu_model != MMU3K ||              && (cpu->cd.mips.cpu_type.mmu_model != MMU3K ||
366              !(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_ISOL_CACHES))              !(cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_ISOL_CACHES))
367  #endif  #endif
 #ifndef MEM_MIPS  
 /*          && !(misc_flags & MEMORY_USER_ACCESS)  */  
368  #ifndef MEM_USERLAND  #ifndef MEM_USERLAND
369              && !(ok & MEMORY_NOT_FULL_PAGE)              && !(ok & MEMORY_NOT_FULL_PAGE)
370  #endif  #endif
 #endif  
371              && !no_exceptions)              && !no_exceptions)
372                  cpu->update_translation_table(cpu, vaddr & ~offset_mask,                  cpu->update_translation_table(cpu, vaddr & ~offset_mask,
373                      memblock, (misc_flags & MEMORY_USER_ACCESS) |                      memblock, (misc_flags & MEMORY_USER_ACCESS) |
374  #if !defined(MEM_MIPS) && !defined(MEM_USERLAND)  #if !defined(MEM_USERLAND)
375                      (cache == CACHE_INSTRUCTION?                      (cache == CACHE_INSTRUCTION?
376                          (writeflag == MEM_WRITE? 1 : 0) : ok - 1),                          (writeflag == MEM_WRITE? 1 : 0) : ok - 1),
377  #else  #else
# Line 501  int MEMORY_RW(struct cpu *cpu, struct me Line 379  int MEMORY_RW(struct cpu *cpu, struct me
379  #endif  #endif
380                      paddr & ~offset_mask);                      paddr & ~offset_mask);
381    
382          /*  Invalidate code translations for the page we are writing to.  */          /*
383          if (writeflag == MEM_WRITE && cpu->invalidate_code_translation != NULL)           *  If writing, or if mapping a page where writing is ok later on,
384             *  then invalidate code translations for the (physical) page address:
385             */
386    
387            if ((writeflag == MEM_WRITE
388    #if !defined(MEM_USERLAND)
389                || (ok == 2 && cache == CACHE_DATA)
390    #endif
391                ) && cpu->invalidate_code_translation != NULL)
392                  cpu->invalidate_code_translation(cpu, paddr, INVALIDATE_PADDR);                  cpu->invalidate_code_translation(cpu, paddr, INVALIDATE_PADDR);
393    
394          if ((paddr&((1<<BITS_PER_MEMBLOCK)-1)) + len > (1<<BITS_PER_MEMBLOCK)) {          if ((paddr&((1<<BITS_PER_MEMBLOCK)-1)) + len > (1<<BITS_PER_MEMBLOCK)) {
# Line 510  int MEMORY_RW(struct cpu *cpu, struct me Line 396  int MEMORY_RW(struct cpu *cpu, struct me
396                  exit(1);                  exit(1);
397          }          }
398    
399          if (writeflag == MEM_WRITE) {          /*  And finally, read or write the data:  */
400                  /*  Ugly optimization, but it works:  */          if (writeflag == MEM_WRITE)
401                  if (len == sizeof(uint32_t) && (offset & 3)==0                  memcpy(memblock + offset, data, len);
402                      && ((size_t)data&3)==0)          else
403                          *(uint32_t *)(memblock + offset) = *(uint32_t *)data;                  memcpy(data, memblock + offset, len);
                 else if (len == sizeof(uint8_t))  
                         *(uint8_t *)(memblock + offset) = *(uint8_t *)data;  
                 else  
                         memcpy(memblock + offset, data, len);  
         } else {  
                 /*  Ugly optimization, but it works:  */  
                 if (len == sizeof(uint32_t) && (offset & 3)==0  
                     && ((size_t)data&3)==0)  
                         *(uint32_t *)data = *(uint32_t *)(memblock + offset);  
                 else if (len == sizeof(uint8_t))  
                         *(uint8_t *)data = *(uint8_t *)(memblock + offset);  
                 else  
                         memcpy(data, memblock + offset, len);  
         }  
   
404    
405  do_return_ok:  do_return_ok:
406          return MEMORY_ACCESS_OK;          return MEMORY_ACCESS_OK;

Legend:
Removed from v.30  
changed lines
  Added in v.42

  ViewVC Help
Powered by ViewVC 1.1.26