/[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 12 by dpavlin, Mon Oct 8 16:18:38 2007 UTC revision 22 by dpavlin, Mon Oct 8 16:19:37 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-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_rw.c,v 1.57 2005/08/12 21:57:02 debug Exp $   *  $Id: memory_rw.c,v 1.82 2005/12/31 15:48:32 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 48  Line 48 
48   *                      a placeholder for data when reading from memory   *                      a placeholder for data when reading from memory
49   *      len             the length of the 'data' buffer   *      len             the length of the 'data' buffer
50   *      writeflag       set to MEM_READ or MEM_WRITE   *      writeflag       set to MEM_READ or MEM_WRITE
51   *      cache_flags     CACHE_{NONE,DATA,INSTRUCTION} | other flags   *      misc_flags      CACHE_{NONE,DATA,INSTRUCTION} | other flags
52   *   *
53   *  If the address indicates access to a memory mapped device, that device'   *  If the address indicates access to a memory mapped device, that device'
54   *  read/write access function is called.   *  read/write access function is called.
# Line 66  Line 66 
66   *  (MEMORY_ACCESS_FAILED is 0.)   *  (MEMORY_ACCESS_FAILED is 0.)
67   */   */
68  int MEMORY_RW(struct cpu *cpu, struct memory *mem, uint64_t vaddr,  int MEMORY_RW(struct cpu *cpu, struct memory *mem, uint64_t vaddr,
69          unsigned char *data, size_t len, int writeflag, int cache_flags)          unsigned char *data, size_t len, int writeflag, int misc_flags)
70  {  {
71  #ifdef MEM_ALPHA  #ifdef MEM_ALPHA
72          const int offset_mask = 0x1fff;          const int offset_mask = 0x1fff;
# Line 83  int MEMORY_RW(struct cpu *cpu, struct me Line 83  int MEMORY_RW(struct cpu *cpu, struct me
83  #ifdef MEM_MIPS  #ifdef MEM_MIPS
84          int bintrans_cached = cpu->machine->bintrans_enable;          int bintrans_cached = cpu->machine->bintrans_enable;
85  #endif  #endif
86          int bintrans_device_danger = 0;          int dyntrans_device_danger = 0;
87    
88          no_exceptions = cache_flags & NO_EXCEPTIONS;          no_exceptions = misc_flags & NO_EXCEPTIONS;
89          cache = cache_flags & CACHE_FLAGS_MASK;          cache = misc_flags & CACHE_FLAGS_MASK;
90    
91  #ifdef MEM_X86  #ifdef MEM_X86
92          /*  Real-mode wrap-around:  */          /*  Real-mode wrap-around:  */
93          if (REAL_MODE && !(cache_flags & PHYSICAL)) {          if (REAL_MODE && !(misc_flags & PHYSICAL)) {
94                  if ((vaddr & 0xffff) + len > 0x10000) {                  if ((vaddr & 0xffff) + len > 0x10000) {
95                          /*  Do one byte at a time:  */                          /*  Do one byte at a time:  */
96                          int res = 0, i;                          int res = 0;
97                            size_t i;
98                          for (i=0; i<len; i++)                          for (i=0; i<len; i++)
99                                  res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,                                  res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,
100                                      writeflag, cache_flags);                                      writeflag, misc_flags);
101                          return res;                          return res;
102                  }                  }
103          }          }
104    
105          /*  Crossing a page boundary? Then do one byte at a time:  */          /*  Crossing a page boundary? Then do one byte at a time:  */
106          if ((vaddr & 0xfff) + len > 0x1000 && !(cache_flags & PHYSICAL)          if ((vaddr & 0xfff) + len > 0x1000 && !(misc_flags & PHYSICAL)
107              && cpu->cd.x86.cr[0] & X86_CR0_PG) {              && cpu->cd.x86.cr[0] & X86_CR0_PG) {
108                  /*  For WRITES: Read ALL BYTES FIRST and write them back!!!                  /*  For WRITES: Read ALL BYTES FIRST and write them back!!!
109                      Then do a write of all the new bytes. This is to make sure                      Then do a write of all the new bytes. This is to make sure
110                      than both pages around the boundary are writable so we don't                      than both pages around the boundary are writable so we don't
111                      do a partial write.  */                      do a partial write.  */
112                  int res = 0, i;                  int res = 0;
113                    size_t i;
114                  if (writeflag == MEM_WRITE) {                  if (writeflag == MEM_WRITE) {
115                          unsigned char tmp;                          unsigned char tmp;
116                          for (i=0; i<len; i++) {                          for (i=0; i<len; i++) {
117                                  res = MEMORY_RW(cpu, mem, vaddr+i, &tmp, 1,                                  res = MEMORY_RW(cpu, mem, vaddr+i, &tmp, 1,
118                                      MEM_READ, cache_flags);                                      MEM_READ, misc_flags);
119                                  if (!res)                                  if (!res)
120                                          return 0;                                          return 0;
121                                  res = MEMORY_RW(cpu, mem, vaddr+i, &tmp, 1,                                  res = MEMORY_RW(cpu, mem, vaddr+i, &tmp, 1,
122                                      MEM_WRITE, cache_flags);                                      MEM_WRITE, misc_flags);
123                                  if (!res)                                  if (!res)
124                                          return 0;                                          return 0;
125                          }                          }
126                          for (i=0; i<len; i++) {                          for (i=0; i<len; i++) {
127                                  res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,                                  res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,
128                                      MEM_WRITE, cache_flags);                                      MEM_WRITE, misc_flags);
129                                  if (!res)                                  if (!res)
130                                          return 0;                                          return 0;
131                          }                          }
# Line 131  int MEMORY_RW(struct cpu *cpu, struct me Line 133  int MEMORY_RW(struct cpu *cpu, struct me
133                          for (i=0; i<len; i++) {                          for (i=0; i<len; i++) {
134                                  /*  Do one byte at a time:  */                                  /*  Do one byte at a time:  */
135                                  res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,                                  res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,
136                                      writeflag, cache_flags);                                      writeflag, misc_flags);
137                                  if (!res) {                                  if (!res) {
138                                          if (cache == CACHE_INSTRUCTION) {                                          if (cache == CACHE_INSTRUCTION) {
139                                                  fatal("FAILED instruction "                                                  fatal("FAILED instruction "
# Line 184  int MEMORY_RW(struct cpu *cpu, struct me Line 186  int MEMORY_RW(struct cpu *cpu, struct me
186          }          }
187  #endif  /*  MEM_MIPS  */  #endif  /*  MEM_MIPS  */
188    
189          if (cache_flags & PHYSICAL || cpu->translate_address == NULL) {          if (misc_flags & PHYSICAL || cpu->translate_address == NULL) {
190                  paddr = vaddr;                  paddr = vaddr;
   
191  #ifdef MEM_ALPHA  #ifdef MEM_ALPHA
192          /*  paddr &= 0x1fffffff;  For testalpha  */                  /*  paddr &= 0x1fffffff;  For testalpha  */
193          paddr &= 0x000003ffffffffffULL;                  paddr &= 0x000003ffffffffffULL;
 #endif  
   
 #ifdef MEM_ARM  
         paddr &= 0x3fffffff;  
 #endif  
   
 #ifdef MEM_IA64  
         /*  For testia64  */  
         paddr &= 0x3fffffff;  
 #endif  
   
 #ifdef MEM_PPC  
         if (cpu->cd.ppc.bits == 32)  
                 paddr &= 0xffffffff;  
194  #endif  #endif
   
195          } else {          } else {
196                  ok = cpu->translate_address(cpu, vaddr, &paddr,                  ok = cpu->translate_address(cpu, vaddr, &paddr,
197                      (writeflag? FLAG_WRITEFLAG : 0) +                      (writeflag? FLAG_WRITEFLAG : 0) +
198                      (no_exceptions? FLAG_NOEXCEPTIONS : 0)                      (no_exceptions? FLAG_NOEXCEPTIONS : 0)
199  #ifdef MEM_X86  #ifdef MEM_X86
200                      + (cache_flags & NO_SEGMENTATION)                      + (misc_flags & NO_SEGMENTATION)
201    #endif
202    #ifdef MEM_ARM
203                        + (misc_flags & MEMORY_USER_ACCESS)
204  #endif  #endif
205                      + (cache==CACHE_INSTRUCTION? FLAG_INSTR : 0));                      + (cache==CACHE_INSTRUCTION? FLAG_INSTR : 0));
206                  /*  If the translation caused an exception, or was invalid in                  /*  If the translation caused an exception, or was invalid in
# Line 224  int MEMORY_RW(struct cpu *cpu, struct me Line 213  int MEMORY_RW(struct cpu *cpu, struct me
213    
214  #ifdef MEM_X86  #ifdef MEM_X86
215          /*  DOS debugging :-)  */          /*  DOS debugging :-)  */
216          if (!quiet_mode && !(cache_flags & PHYSICAL)) {          if (!quiet_mode && !(misc_flags & PHYSICAL)) {
217                  if (paddr >= 0x400 && paddr <= 0x4ff)                  if (paddr >= 0x400 && paddr <= 0x4ff)
218                          debug("{ PC BIOS DATA AREA: %s 0x%x }\n", writeflag ==                          debug("{ PC BIOS DATA AREA: %s 0x%x }\n", writeflag ==
219                              MEM_WRITE? "writing to" : "reading from",                              MEM_WRITE? "writing to" : "reading from",
# Line 280  have_paddr: Line 269  have_paddr:
269          /*          /*
270           *  Memory mapped device?           *  Memory mapped device?
271           *           *
272           *  TODO: this is utterly slow.           *  TODO: if paddr < base, but len enough, then the device should
273           *  TODO2: if paddr<base, but len enough, then we should write           *  still be written to!
          *  to a device to  
274           */           */
275          if (paddr >= mem->mmap_dev_minaddr && paddr < mem->mmap_dev_maxaddr) {          if (paddr >= mem->mmap_dev_minaddr && paddr < mem->mmap_dev_maxaddr) {
276                  uint64_t orig_paddr = paddr;                  uint64_t orig_paddr = paddr;
277                  int i, start, res;                  int i, start, end, res;
278    
279                  /*                  /*
280                   *  Really really slow, but unfortunately necessary. This is                   *  Really really slow, but unfortunately necessary. This is
# Line 296  have_paddr: Line 284  have_paddr:
284                   *      b) offsets 0x124..0x777 are a device                   *      b) offsets 0x124..0x777 are a device
285                   *                   *
286                   *      1) a read is done from offset 0x100. the page is                   *      1) a read is done from offset 0x100. the page is
287                   *         added to the bintrans system as a "RAM" page                   *         added to the dyntrans system as a "RAM" page
288                   *      2) a bintranslated read is done from offset 0x200,                   *      2) a dyntranslated read is done from offset 0x200,
289                   *         which should access the device, but since the                   *         which should access the device, but since the
290                   *         entire page is added, it will access non-existant                   *         entire page is added, it will access non-existant
291                   *         RAM instead, without warning.                   *         RAM instead, without warning.
292                   *                   *
293                   *  Setting bintrans_device_danger = 1 on accesses which are                   *  Setting dyntrans_device_danger = 1 on accesses which are
294                   *  on _any_ offset on pages that are device mapped avoids                   *  on _any_ offset on pages that are device mapped avoids
295                   *  this problem, but it is probably not very fast.                   *  this problem, but it is probably not very fast.
296                     *
297                     *  TODO: Convert this into a quick (multi-level, 64-bit)
298                     *  address space lookup, to find dangerous pages.
299                   */                   */
300    #if 1
301                  for (i=0; i<mem->n_mmapped_devices; i++)                  for (i=0; i<mem->n_mmapped_devices; i++)
302                          if (paddr >= (mem->dev_baseaddr[i] & ~offset_mask) &&                          if (paddr >= (mem->dev_baseaddr[i] & ~offset_mask) &&
303                              paddr <= ((mem->dev_baseaddr[i] +                              paddr <= ((mem->dev_endaddr[i]-1) | offset_mask)) {
304                              mem->dev_length[i] - 1) | offset_mask)) {                                  dyntrans_device_danger = 1;
                                 bintrans_device_danger = 1;  
305                                  break;                                  break;
306                          }                          }
307    #endif
308    
309                  i = start = mem->last_accessed_device;                  start = 0; end = mem->n_mmapped_devices - 1;
310                    i = mem->last_accessed_device;
311    
312                  /*  Scan through all devices:  */                  /*  Scan through all devices:  */
313                  do {                  do {
314                          if (paddr >= mem->dev_baseaddr[i] &&                          if (paddr >= mem->dev_baseaddr[i] &&
315                              paddr < mem->dev_baseaddr[i] + mem->dev_length[i]) {                              paddr < mem->dev_endaddr[i]) {
316                                  /*  Found a device, let's access it:  */                                  /*  Found a device, let's access it:  */
317                                  mem->last_accessed_device = i;                                  mem->last_accessed_device = i;
318    
# Line 328  have_paddr: Line 321  have_paddr:
321                                          len = mem->dev_length[i] - paddr;                                          len = mem->dev_length[i] - paddr;
322    
323                                  if (cpu->update_translation_table != NULL &&                                  if (cpu->update_translation_table != NULL &&
324                                      mem->dev_flags[i] & MEM_DYNTRANS_OK) {                                      !(ok & MEMORY_NOT_FULL_PAGE) &&
325                                        mem->dev_flags[i] & DM_DYNTRANS_OK) {
326                                          int wf = writeflag == MEM_WRITE? 1 : 0;                                          int wf = writeflag == MEM_WRITE? 1 : 0;
327                                            unsigned char *host_addr;
328    
329                                          if (writeflag) {                                          if (!(mem->dev_flags[i] &
330                                                DM_DYNTRANS_WRITE_OK))
331                                                    wf = 0;
332    
333                                            if (writeflag && wf) {
334                                                  if (paddr < mem->                                                  if (paddr < mem->
335                                                      dev_dyntrans_write_low[i])                                                      dev_dyntrans_write_low[i])
336                                                          mem->                                                          mem->
# Line 346  have_paddr: Line 345  have_paddr:
345                                                              offset_mask;                                                              offset_mask;
346                                          }                                          }
347    
348                                          if (!(mem->dev_flags[i] &                                          if (mem->dev_flags[i] &
349                                              MEM_DYNTRANS_WRITE_OK))                                              DM_EMULATED_RAM) {
350                                                  wf = 0;                                                  /*  MEM_WRITE to force the page
351                                                        to be allocated, if it
352                                                        wasn't already  */
353                                                    uint64_t *pp = (uint64_t *)
354                                                        mem->dev_dyntrans_data[i];
355                                                    uint64_t p = orig_paddr - *pp;
356                                                    host_addr =
357                                                        memory_paddr_to_hostaddr(
358                                                        mem, p, MEM_WRITE)
359                                                        + (p & ~offset_mask
360                                                        & ((1 <<
361                                                        BITS_PER_MEMBLOCK) - 1));
362                                            } else {
363                                                    host_addr =
364                                                        mem->dev_dyntrans_data[i] +
365                                                        (paddr & ~offset_mask);
366                                            }
367                                          cpu->update_translation_table(cpu,                                          cpu->update_translation_table(cpu,
368                                              vaddr & ~offset_mask,                                              vaddr & ~offset_mask, host_addr,
                                             mem->dev_dyntrans_data[i] +  
                                             (paddr & ~offset_mask),  
369                                              wf, orig_paddr & ~offset_mask);                                              wf, orig_paddr & ~offset_mask);
370                                  }                                  }
371    
372                                  res = 0;                                  res = 0;
373                                  if (!no_exceptions || (mem->dev_flags[i] &                                  if (!no_exceptions || (mem->dev_flags[i] &
374                                      MEM_READING_HAS_NO_SIDE_EFFECTS))                                      DM_READS_HAVE_NO_SIDE_EFFECTS))
375                                          res = mem->dev_f[i](cpu, mem, paddr,                                          res = mem->dev_f[i](cpu, mem, paddr,
376                                              data, len, writeflag,                                              data, len, writeflag,
377                                              mem->dev_extra[i]);                                              mem->dev_extra[i]);
# Line 368  have_paddr: Line 380  have_paddr:
380                                  if (res == 0)                                  if (res == 0)
381                                          res = -1;                                          res = -1;
382    
383    #ifdef MEM_MIPS
384                                  cpu->cd.mips.instruction_delay +=                                  cpu->cd.mips.instruction_delay +=
385                                      ( (abs(res) - 1) *                                      ( (abs(res) - 1) *
386                                       cpu->cd.mips.cpu_type.instrs_per_cycle );                                       cpu->cd.mips.cpu_type.instrs_per_cycle );
387  #endif  #endif
388    #endif
389    
390  #ifndef MEM_X86  #ifndef MEM_X86
391                                  /*                                  /*
# Line 393  have_paddr: Line 407  have_paddr:
407                                  goto do_return_ok;                                  goto do_return_ok;
408                          }                          }
409    
410                          i ++;                          if (paddr < mem->dev_baseaddr[i])
411                          if (i == mem->n_mmapped_devices)                                  end = i - 1;
412                                  i = 0;                          if (paddr >= mem->dev_endaddr[i])
413                  } while (i != start);                                  start = i + 1;
414                            i = (start + end) >> 1;
415                    } while (start <= end);
416          }          }
417    
418    
# Line 408  have_paddr: Line 424  have_paddr:
424          switch (cpu->cd.mips.cpu_type.mmu_model) {          switch (cpu->cd.mips.cpu_type.mmu_model) {
425          case MMU3K:          case MMU3K:
426                  /*  if not uncached addess  (TODO: generalize this)  */                  /*  if not uncached addess  (TODO: generalize this)  */
427                  if (!(cache_flags & PHYSICAL) && cache != CACHE_NONE &&                  if (!(misc_flags & PHYSICAL) && cache != CACHE_NONE &&
428                      !((vaddr & 0xffffffffULL) >= 0xa0000000ULL &&                      !((vaddr & 0xffffffffULL) >= 0xa0000000ULL &&
429                        (vaddr & 0xffffffffULL) <= 0xbfffffffULL)) {                        (vaddr & 0xffffffffULL) <= 0xbfffffffULL)) {
430                          if (memory_cache_R3000(cpu, cache, paddr,                          if (memory_cache_R3000(cpu, cache, paddr,
# Line 440  have_paddr: Line 456  have_paddr:
456                  {                  {
457                          if (paddr >= mem->physical_max) {                          if (paddr >= mem->physical_max) {
458                                  char *symbol;                                  char *symbol;
                                 uint64_t old_pc;  
459                                  uint64_t offset;                                  uint64_t offset;
   
460  #ifdef MEM_MIPS  #ifdef MEM_MIPS
461                                  old_pc = cpu->cd.mips.pc_last;                                  uint64_t old_pc = cpu->cd.mips.pc_last;
462  #else  #else
463                                  /*  Default instruction size on most                                  uint64_t old_pc = cpu->pc;
                                     RISC archs is 32 bits:  */  
                                 old_pc = cpu->pc - sizeof(uint32_t);  
464  #endif  #endif
465    
466                                  /*  This allows for example OS kernels to probe                                  /*  This allows for example OS kernels to probe
# Line 548  have_paddr: Line 560  have_paddr:
560    
561          /*          /*
562           *  Uncached access:           *  Uncached access:
563             *
564             *  1)  Translate the physical address to a host address.
565             *
566             *  2)  Insert this virtual->physical->host translation into the
567             *      fast translation arrays (using update_translation_table()).
568             *
569             *  3)  If this was a Write, then invalidate any code translations
570             *      in that page.
571           */           */
572          memblock = memory_paddr_to_hostaddr(mem, paddr, writeflag);          memblock = memory_paddr_to_hostaddr(mem, paddr, writeflag);
573          if (memblock == NULL) {          if (memblock == NULL) {
# Line 558  have_paddr: Line 578  have_paddr:
578    
579          offset = paddr & ((1 << BITS_PER_MEMBLOCK) - 1);          offset = paddr & ((1 << BITS_PER_MEMBLOCK) - 1);
580    
581          if (cpu->update_translation_table != NULL && !bintrans_device_danger)          if (cpu->update_translation_table != NULL && !dyntrans_device_danger
582    #ifndef MEM_MIPS
583    /*          && !(misc_flags & MEMORY_USER_ACCESS)  */
584    #ifndef MEM_USERLAND
585                && !(ok & MEMORY_NOT_FULL_PAGE)
586    #endif
587    #endif
588                && !no_exceptions)
589                  cpu->update_translation_table(cpu, vaddr & ~offset_mask,                  cpu->update_translation_table(cpu, vaddr & ~offset_mask,
590                      memblock + (offset & ~offset_mask),                      memblock + (offset & ~offset_mask),
591  #if 0                      (misc_flags & MEMORY_USER_ACCESS) |
592                      cache == CACHE_INSTRUCTION?  #ifndef MEM_MIPS
593                          (writeflag == MEM_WRITE? 1 : 0)                      (cache == CACHE_INSTRUCTION? TLB_CODE : 0) |
594                          : ok - 1,  #endif
595    #if !defined(MEM_MIPS) && !defined(MEM_USERLAND)
596                        (cache == CACHE_INSTRUCTION?
597                            (writeflag == MEM_WRITE? 1 : 0) : ok - 1),
598  #else  #else
599                      writeflag == MEM_WRITE? 1 : 0,                      (writeflag == MEM_WRITE? 1 : 0),
600  #endif  #endif
601                      paddr & ~offset_mask);                      paddr & ~offset_mask);
602    
603            /*  Invalidate code translations for the page we are writing to.  */
604            if (writeflag == MEM_WRITE && cpu->invalidate_code_translation != NULL)
605                    cpu->invalidate_code_translation(cpu, paddr, INVALIDATE_PADDR);
606    
607          if (writeflag == MEM_WRITE) {          if (writeflag == MEM_WRITE) {
608                  /*  Ugly optimization, but it works:  */                  /*  Ugly optimization, but it works:  */
609                  if (len == sizeof(uint32_t) && (offset & 3)==0                  if (len == sizeof(uint32_t) && (offset & 3)==0

Legend:
Removed from v.12  
changed lines
  Added in v.22

  ViewVC Help
Powered by ViewVC 1.1.26