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

Annotation of /trunk/src/memory_rw.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (hide annotations)
Mon Oct 8 16:19:23 2007 UTC (16 years, 7 months ago) by dpavlin
File MIME type: text/plain
File size: 17622 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1055 2005/11/25 22:48:36 debug Exp $
20051031	Adding disassembly support for more ARM instructions (clz,
		smul* etc), and adding a hack to support "new tiny" pages
		for StrongARM.
20051101	Minor documentation updates (NetBSD 2.0.2 -> 2.1, and OpenBSD
		3.7 -> 3.8, and lots of testing).
		Changing from 1-sector PIO mode 0 transfers to 128-sector PIO
		mode 3 (in dev_wdc).
		Various minor ARM dyntrans updates (pc-relative loads from
		within the same page as the instruction are now treated as
		constant "mov").
20051102	Re-enabling instruction combinations (they were accidentally
		disabled).
		Dyntrans TLB entries are now overwritten using a round-robin
		scheme instead of randomly. This increases performance.
		Fixing a typo in file.c (thanks to Chuan-Hua Chang for
		noticing it).
		Experimenting with adding ATAPI support to dev_wdc (to make
		emulated *BSD detect cdroms as cdroms, not harddisks).
20051104	Various minor updates.
20051105	Continuing on the ATAPI emulation. Seems to work well enough
		for a NetBSD/cats installation, but not OpenBSD/cats.
		Various other updates.
20051106	Modifying the -Y command line option to allow scaleup with
		certain graphic controllers (only dev_vga so far), not just
		scaledown.
		Some minor dyntrans cleanups.
20051107	Beginning a cleanup up the PCI subsystem (removing the
		read_register hack, etc).
20051108	Continuing the cleanup; splitting up some pci devices into a
		normal autodev device and some separate pci glue code.
20051109	Continuing on the PCI bus stuff; all old pci_*.c have been
		incorporated into normal devices and/or rewritten as glue code
		only, adding a dummy Intel 82371AB PIIX4 for Malta (not really
		tested yet).
		Minor pckbc fix so that Linux doesn't complain.
		Working on the DEC 21143 NIC (ethernet mac rom stuff mostly).
		Various other minor fixes.
20051110	Some more ARM dyntrans fine-tuning (e.g. some instruction
		combinations (cmps followed by conditional branch within the
		same page) and special cases for DPIs with regform when the
		shifter isn't used).
20051111	ARM dyntrans updates: O(n)->O(1) for just-mark-as-non-
		writable in the generic pc_to_pointers function, and some other
		minor hacks.
		Merging Cobalt and evbmips (Malta) ISA interrupt handling,
		and some minor fixes to allow Linux to accept harddisk irqs.
20051112	Minor device updates (pckbc, dec21143, lpt, ...), most
		importantly fixing the ALI M1543/M5229 so that harddisk irqs
		work with Linux/CATS.
20051113	Some more generalizations of the PCI subsystem.
		Finally took the time to add a hack for SCSI CDROM TOCs; this
		enables OpenBSD to use partition 'a' (as needed by the OpenBSD
		installer), and Windows NT's installer to get a bit further.
		Also fixing dev_wdc to allow Linux to detect ATAPI CDROMs.
		Continuing on the DEC 21143.
20051114	Minor ARM dyntrans tweaks; ARM cmps+branch optimization when
		comparing with 0, and generalizing the xchg instr. comb.
		Adding disassembly of ARM mrrc/mcrr and q{,d}{add,sub}.
20051115	Continuing on various PPC things (BATs, other address trans-
		lation things, various loads/stores, BeBox emulation, etc.).
		Beginning to work on PPC interrupt/exception support.
20051116	Factoring out some code which initializes legacy ISA devices
		from those machines that use them (bus_isa).
		Continuing on PPC interrupt/exception support.
20051117	Minor Malta fixes: RTC year offset = 80, disabling a speed hack
		which caused NetBSD to detect a too fast cpu, and adding a new
		hack to make Linux detect a faster cpu.
		Continuing on the Artesyn PM/PPC emulation mode.
		Adding an Algor emulation skeleton (P4032 and P5064);
		implementing some of the basics.
		Continuing on PPC emulation in general; usage of unimplemented
		SPRs is now easier to track, continuing on memory/exception
		related issues, etc.
20051118	More work on PPC emulation (tgpr0..3, exception handling,
		memory stuff, syscalls, etc.).
20051119	Changing the ARM dyntrans code to mostly use cpu->pc, and not
		necessarily use arm reg 15. Seems to work.
		Various PPC updates; continuing on the PReP emulation mode.
20051120	Adding a workaround/hack to dev_mc146818 to allow NetBSD/prep
		to detect the clock.
20051121	More cleanup of the PCI bus (memory and I/O bases, etc).
		Continuing on various PPC things (decrementer and timebase,
		WDCs on obio (on PReP) use irq 13, not 14/15).
20051122	Continuing on the CPC700 controller (interrupts etc) for PMPPC,
		and on PPC stuff in general.
		Finally! After some bug fixes to the virtual to physical addr
		translation, NetBSD/{prep,pmppc} 2.1 reach userland and are
		stable enough to be interacted with.
		More PCI updates; reverse-endian device access for PowerPC etc.
20051123	Generalizing the IEEE floating point subsystem (moving it out
		from src/cpus/cpu_mips_coproc.c into a new src/float_emul.c).
		Input via slave xterms was sometimes not really working; fixing
		this for ns16550, and a warning message is now displayed if
		multiple non-xterm consoles are active.
		Adding some PPC floating point support, etc.
		Various interrupt related updates (dev_wdc, _ns16550, _8259,
		and the isa32 common code in machine.c).
		NetBSD/prep can now be installed! :-) (Well, with some manual
		commands necessary before running sysinst.) Updating the
		documentation and various other things to reflect this.
20051124	Various minor documentation updates.
		Continuing the work on the DEC 21143 NIC.
20051125	LOTS of work on the 21143. Both OpenBSD and NetBSD work fine
		with it now, except that OpenBSD sometimes gives a time-out
		warning.
		Minor documentation updates.

==============  RELEASE 0.3.7  ==============


1 dpavlin 2 /*
2     * Copyright (C) 2003-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 20 * $Id: memory_rw.c,v 1.80 2005/11/20 11:28:44 debug Exp $
29 dpavlin 2 *
30     * Generic memory_rw(), with special hacks for specific CPU families.
31     *
32     * Example for inclusion from memory_mips.c:
33     *
34     * MEMORY_RW should be mips_memory_rw
35     * MEM_MIPS should be defined
36     */
37    
38    
39     /*
40     * memory_rw():
41     *
42     * Read or write data from/to memory.
43     *
44     * cpu the cpu doing the read/write
45     * mem the memory object to use
46     * vaddr the virtual address
47     * data a pointer to the data to be written to memory, or
48     * a placeholder for data when reading from memory
49     * len the length of the 'data' buffer
50     * writeflag set to MEM_READ or MEM_WRITE
51 dpavlin 20 * misc_flags CACHE_{NONE,DATA,INSTRUCTION} | other flags
52 dpavlin 2 *
53     * If the address indicates access to a memory mapped device, that device'
54     * read/write access function is called.
55     *
56     * If instruction latency/delay support is enabled, then
57     * cpu->instruction_delay is increased by the number of instruction to
58     * delay execution.
59     *
60     * This function should not be called with cpu == NULL.
61     *
62     * Returns one of the following:
63     * MEMORY_ACCESS_FAILED
64     * MEMORY_ACCESS_OK
65     *
66     * (MEMORY_ACCESS_FAILED is 0.)
67     */
68     int MEMORY_RW(struct cpu *cpu, struct memory *mem, uint64_t vaddr,
69 dpavlin 20 unsigned char *data, size_t len, int writeflag, int misc_flags)
70 dpavlin 2 {
71 dpavlin 12 #ifdef MEM_ALPHA
72     const int offset_mask = 0x1fff;
73     #else
74     const int offset_mask = 0xfff;
75     #endif
76    
77 dpavlin 2 #ifndef MEM_USERLAND
78     int ok = 1;
79     #endif
80     uint64_t paddr;
81     int cache, no_exceptions, offset;
82     unsigned char *memblock;
83 dpavlin 12 #ifdef MEM_MIPS
84 dpavlin 2 int bintrans_cached = cpu->machine->bintrans_enable;
85 dpavlin 12 #endif
86 dpavlin 4 int bintrans_device_danger = 0;
87 dpavlin 12
88 dpavlin 20 no_exceptions = misc_flags & NO_EXCEPTIONS;
89     cache = misc_flags & CACHE_FLAGS_MASK;
90 dpavlin 2
91 dpavlin 4 #ifdef MEM_X86
92 dpavlin 6 /* Real-mode wrap-around: */
93 dpavlin 20 if (REAL_MODE && !(misc_flags & PHYSICAL)) {
94 dpavlin 6 if ((vaddr & 0xffff) + len > 0x10000) {
95     /* Do one byte at a time: */
96     int res = 0, i;
97     for (i=0; i<len; i++)
98     res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,
99 dpavlin 20 writeflag, misc_flags);
100 dpavlin 6 return res;
101     }
102     }
103 dpavlin 4
104 dpavlin 6 /* Crossing a page boundary? Then do one byte at a time: */
105 dpavlin 20 if ((vaddr & 0xfff) + len > 0x1000 && !(misc_flags & PHYSICAL)
106 dpavlin 6 && cpu->cd.x86.cr[0] & X86_CR0_PG) {
107     /* For WRITES: Read ALL BYTES FIRST and write them back!!!
108     Then do a write of all the new bytes. This is to make sure
109     than both pages around the boundary are writable so we don't
110     do a partial write. */
111     int res = 0, i;
112     if (writeflag == MEM_WRITE) {
113     unsigned char tmp;
114     for (i=0; i<len; i++) {
115     res = MEMORY_RW(cpu, mem, vaddr+i, &tmp, 1,
116 dpavlin 20 MEM_READ, misc_flags);
117 dpavlin 6 if (!res)
118 dpavlin 4 return 0;
119 dpavlin 6 res = MEMORY_RW(cpu, mem, vaddr+i, &tmp, 1,
120 dpavlin 20 MEM_WRITE, misc_flags);
121 dpavlin 6 if (!res)
122     return 0;
123     }
124     for (i=0; i<len; i++) {
125     res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,
126 dpavlin 20 MEM_WRITE, misc_flags);
127 dpavlin 6 if (!res)
128     return 0;
129     }
130     } else {
131     for (i=0; i<len; i++) {
132     /* Do one byte at a time: */
133     res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,
134 dpavlin 20 writeflag, misc_flags);
135 dpavlin 6 if (!res) {
136     if (cache == CACHE_INSTRUCTION) {
137     fatal("FAILED instruction "
138     "fetch across page boundar"
139     "y: todo. vaddr=0x%08x\n",
140     (int)vaddr);
141     cpu->running = 0;
142     }
143     return 0;
144 dpavlin 4 }
145     }
146     }
147 dpavlin 6 return res;
148 dpavlin 4 }
149 dpavlin 6 #endif /* X86 */
150 dpavlin 4
151 dpavlin 2 #ifdef MEM_MIPS
152     if (bintrans_cached) {
153     if (cache == CACHE_INSTRUCTION) {
154     cpu->cd.mips.pc_bintrans_host_4kpage = NULL;
155     cpu->cd.mips.pc_bintrans_paddr_valid = 0;
156     }
157     }
158     #endif /* MEM_MIPS */
159    
160     #ifdef MEM_USERLAND
161 dpavlin 12 #ifdef MEM_ALPHA
162     paddr = vaddr;
163     #else
164 dpavlin 2 paddr = vaddr & 0x7fffffff;
165 dpavlin 12 #endif
166 dpavlin 2 goto have_paddr;
167     #endif
168    
169     #ifndef MEM_USERLAND
170     #ifdef MEM_MIPS
171     /*
172     * For instruction fetch, are we on the same page as the last
173     * instruction we fetched?
174     *
175     * NOTE: There's no need to check this stuff here if this address
176     * is known to be in host ram, as it's done at instruction fetch
177     * time in cpu.c! Only check if _host_4k_page == NULL.
178     */
179     if (cache == CACHE_INSTRUCTION &&
180     cpu->cd.mips.pc_last_host_4k_page == NULL &&
181     (vaddr & ~0xfff) == cpu->cd.mips.pc_last_virtual_page) {
182     paddr = cpu->cd.mips.pc_last_physical_page | (vaddr & 0xfff);
183     goto have_paddr;
184     }
185     #endif /* MEM_MIPS */
186    
187 dpavlin 20 if (misc_flags & PHYSICAL || cpu->translate_address == NULL) {
188 dpavlin 2 paddr = vaddr;
189 dpavlin 12 #ifdef MEM_ALPHA
190 dpavlin 14 /* paddr &= 0x1fffffff; For testalpha */
191     paddr &= 0x000003ffffffffffULL;
192 dpavlin 12 #endif
193 dpavlin 2 } else {
194     ok = cpu->translate_address(cpu, vaddr, &paddr,
195     (writeflag? FLAG_WRITEFLAG : 0) +
196     (no_exceptions? FLAG_NOEXCEPTIONS : 0)
197 dpavlin 6 #ifdef MEM_X86
198 dpavlin 20 + (misc_flags & NO_SEGMENTATION)
199 dpavlin 6 #endif
200 dpavlin 14 #ifdef MEM_ARM
201 dpavlin 20 + (misc_flags & MEMORY_USER_ACCESS)
202 dpavlin 14 #endif
203 dpavlin 2 + (cache==CACHE_INSTRUCTION? FLAG_INSTR : 0));
204     /* If the translation caused an exception, or was invalid in
205     some way, we simply return without doing the memory
206     access: */
207     if (!ok)
208     return MEMORY_ACCESS_FAILED;
209     }
210    
211    
212 dpavlin 6 #ifdef MEM_X86
213     /* DOS debugging :-) */
214 dpavlin 20 if (!quiet_mode && !(misc_flags & PHYSICAL)) {
215 dpavlin 6 if (paddr >= 0x400 && paddr <= 0x4ff)
216     debug("{ PC BIOS DATA AREA: %s 0x%x }\n", writeflag ==
217     MEM_WRITE? "writing to" : "reading from",
218     (int)paddr);
219     #if 0
220     if (paddr >= 0xf0000 && paddr <= 0xfffff)
221     debug("{ BIOS ACCESS: %s 0x%x }\n",
222     writeflag == MEM_WRITE? "writing to" :
223     "reading from", (int)paddr);
224     #endif
225     }
226     #endif
227    
228 dpavlin 2 #ifdef MEM_MIPS
229     /*
230     * If correct cache emulation is enabled, and we need to simluate
231     * cache misses even from the instruction cache, we can't run directly
232     * from a host page. :-/
233     */
234     #if defined(ENABLE_CACHE_EMULATION) && defined(ENABLE_INSTRUCTION_DELAYS)
235     #else
236     if (cache == CACHE_INSTRUCTION) {
237     cpu->cd.mips.pc_last_virtual_page = vaddr & ~0xfff;
238     cpu->cd.mips.pc_last_physical_page = paddr & ~0xfff;
239     cpu->cd.mips.pc_last_host_4k_page = NULL;
240    
241     /* _last_host_4k_page will be set to 1 further down,
242     if the page is actually in host ram */
243     }
244     #endif
245     #endif /* MEM_MIPS */
246     #endif /* ifndef MEM_USERLAND */
247    
248    
249 dpavlin 4 #if defined(MEM_MIPS) || defined(MEM_USERLAND)
250 dpavlin 2 have_paddr:
251 dpavlin 4 #endif
252 dpavlin 2
253    
254     #ifdef MEM_MIPS
255     /* TODO: How about bintrans vs cache emulation? */
256     if (bintrans_cached) {
257     if (cache == CACHE_INSTRUCTION) {
258     cpu->cd.mips.pc_bintrans_paddr_valid = 1;
259     cpu->cd.mips.pc_bintrans_paddr = paddr;
260     }
261     }
262     #endif /* MEM_MIPS */
263    
264    
265    
266     #ifndef MEM_USERLAND
267     /*
268     * Memory mapped device?
269     *
270     * TODO: this is utterly slow.
271     * TODO2: if paddr<base, but len enough, then we should write
272     * to a device to
273     */
274     if (paddr >= mem->mmap_dev_minaddr && paddr < mem->mmap_dev_maxaddr) {
275     uint64_t orig_paddr = paddr;
276     int i, start, res;
277 dpavlin 4
278     /*
279     * Really really slow, but unfortunately necessary. This is
280     * to avoid the folowing scenario:
281     *
282     * a) offsets 0x000..0x123 are normal memory
283     * b) offsets 0x124..0x777 are a device
284     *
285     * 1) a read is done from offset 0x100. the page is
286     * added to the bintrans system as a "RAM" page
287     * 2) a bintranslated read is done from offset 0x200,
288     * which should access the device, but since the
289     * entire page is added, it will access non-existant
290     * RAM instead, without warning.
291     *
292     * Setting bintrans_device_danger = 1 on accesses which are
293     * on _any_ offset on pages that are device mapped avoids
294     * this problem, but it is probably not very fast.
295     */
296 dpavlin 12 for (i=0; i<mem->n_mmapped_devices; i++)
297     if (paddr >= (mem->dev_baseaddr[i] & ~offset_mask) &&
298 dpavlin 18 paddr <= ((mem->dev_endaddr[i]-1) | offset_mask)) {
299 dpavlin 12 bintrans_device_danger = 1;
300     break;
301     }
302 dpavlin 4
303 dpavlin 2 i = start = mem->last_accessed_device;
304    
305     /* Scan through all devices: */
306     do {
307     if (paddr >= mem->dev_baseaddr[i] &&
308 dpavlin 18 paddr < mem->dev_endaddr[i]) {
309 dpavlin 2 /* Found a device, let's access it: */
310     mem->last_accessed_device = i;
311    
312     paddr -= mem->dev_baseaddr[i];
313     if (paddr + len > mem->dev_length[i])
314     len = mem->dev_length[i] - paddr;
315    
316 dpavlin 12 if (cpu->update_translation_table != NULL &&
317 dpavlin 20 !(ok & MEMORY_NOT_FULL_PAGE) &&
318     mem->dev_flags[i] & DM_DYNTRANS_OK) {
319 dpavlin 2 int wf = writeflag == MEM_WRITE? 1 : 0;
320 dpavlin 18 unsigned char *host_addr;
321 dpavlin 2
322 dpavlin 18 if (!(mem->dev_flags[i] &
323 dpavlin 20 DM_DYNTRANS_WRITE_OK))
324 dpavlin 18 wf = 0;
325    
326     if (writeflag && wf) {
327 dpavlin 2 if (paddr < mem->
328 dpavlin 12 dev_dyntrans_write_low[i])
329 dpavlin 2 mem->
330 dpavlin 12 dev_dyntrans_write_low
331     [i] = paddr &
332     ~offset_mask;
333     if (paddr >= mem->
334     dev_dyntrans_write_high[i])
335 dpavlin 2 mem->
336 dpavlin 12 dev_dyntrans_write_high
337     [i] = paddr |
338     offset_mask;
339 dpavlin 2 }
340    
341 dpavlin 18 if (mem->dev_flags[i] &
342 dpavlin 20 DM_EMULATED_RAM) {
343 dpavlin 18 /* MEM_WRITE to force the page
344     to be allocated, if it
345     wasn't already */
346     uint64_t *pp = (uint64_t *)
347     mem->dev_dyntrans_data[i];
348     uint64_t p = orig_paddr - *pp;
349     host_addr =
350     memory_paddr_to_hostaddr(
351     mem, p, MEM_WRITE)
352     + (p & ~offset_mask
353     & ((1 <<
354     BITS_PER_MEMBLOCK) - 1));
355     } else {
356     host_addr =
357     mem->dev_dyntrans_data[i] +
358     (paddr & ~offset_mask);
359     }
360 dpavlin 12 cpu->update_translation_table(cpu,
361 dpavlin 18 vaddr & ~offset_mask, host_addr,
362 dpavlin 12 wf, orig_paddr & ~offset_mask);
363 dpavlin 2 }
364    
365 dpavlin 6 res = 0;
366     if (!no_exceptions || (mem->dev_flags[i] &
367 dpavlin 20 DM_READS_HAVE_NO_SIDE_EFFECTS))
368 dpavlin 6 res = mem->dev_f[i](cpu, mem, paddr,
369     data, len, writeflag,
370     mem->dev_extra[i]);
371 dpavlin 2
372     #ifdef ENABLE_INSTRUCTION_DELAYS
373     if (res == 0)
374     res = -1;
375    
376 dpavlin 18 #ifdef MEM_MIPS
377 dpavlin 2 cpu->cd.mips.instruction_delay +=
378     ( (abs(res) - 1) *
379     cpu->cd.mips.cpu_type.instrs_per_cycle );
380     #endif
381 dpavlin 18 #endif
382 dpavlin 6
383     #ifndef MEM_X86
384 dpavlin 2 /*
385     * If accessing the memory mapped device
386     * failed, then return with a DBE exception.
387     */
388 dpavlin 6 if (res <= 0 && !no_exceptions) {
389 dpavlin 2 debug("%s device '%s' addr %08lx "
390     "failed\n", writeflag?
391     "writing to" : "reading from",
392     mem->dev_name[i], (long)paddr);
393     #ifdef MEM_MIPS
394     mips_cpu_exception(cpu, EXCEPTION_DBE,
395     0, vaddr, 0, 0, 0, 0);
396     #endif
397     return MEMORY_ACCESS_FAILED;
398     }
399 dpavlin 6 #endif
400 dpavlin 2 goto do_return_ok;
401     }
402    
403     i ++;
404     if (i == mem->n_mmapped_devices)
405     i = 0;
406     } while (i != start);
407     }
408    
409    
410     #ifdef MEM_MIPS
411     /*
412     * Data and instruction cache emulation:
413     */
414    
415     switch (cpu->cd.mips.cpu_type.mmu_model) {
416     case MMU3K:
417     /* if not uncached addess (TODO: generalize this) */
418 dpavlin 20 if (!(misc_flags & PHYSICAL) && cache != CACHE_NONE &&
419 dpavlin 2 !((vaddr & 0xffffffffULL) >= 0xa0000000ULL &&
420     (vaddr & 0xffffffffULL) <= 0xbfffffffULL)) {
421     if (memory_cache_R3000(cpu, cache, paddr,
422     writeflag, len, data))
423     goto do_return_ok;
424     }
425     break;
426     default:
427     /* R4000 etc */
428     /* TODO */
429     ;
430     }
431     #endif /* MEM_MIPS */
432    
433    
434     /* Outside of physical RAM? */
435     if (paddr >= mem->physical_max) {
436 dpavlin 6 #ifdef MEM_MIPS
437     if ((paddr & 0xffffc00000ULL) == 0x1fc00000) {
438 dpavlin 2 /* Ok, this is PROM stuff */
439     } else if ((paddr & 0xfffff00000ULL) == 0x1ff00000) {
440     /* Sprite reads from this area of memory... */
441     /* TODO: is this still correct? */
442     if (writeflag == MEM_READ)
443     memset(data, 0, len);
444     goto do_return_ok;
445 dpavlin 6 } else
446     #endif /* MIPS */
447     {
448     if (paddr >= mem->physical_max) {
449 dpavlin 2 char *symbol;
450 dpavlin 12 uint64_t offset;
451 dpavlin 2 #ifdef MEM_MIPS
452 dpavlin 20 uint64_t old_pc = cpu->cd.mips.pc_last;
453 dpavlin 12 #else
454 dpavlin 20 uint64_t old_pc = cpu->pc;
455 dpavlin 2 #endif
456 dpavlin 12
457 dpavlin 6 /* This allows for example OS kernels to probe
458     memory a few KBs past the end of memory,
459     without giving too many warnings. */
460 dpavlin 12 if (!quiet_mode && !no_exceptions && paddr >=
461 dpavlin 6 mem->physical_max + 0x40000) {
462 dpavlin 2 fatal("[ memory_rw(): writeflag=%i ",
463     writeflag);
464     if (writeflag) {
465     unsigned int i;
466     debug("data={", writeflag);
467     if (len > 16) {
468     int start2 = len-16;
469     for (i=0; i<16; i++)
470     debug("%s%02x",
471     i?",":"",
472     data[i]);
473     debug(" .. ");
474     if (start2 < 16)
475     start2 = 16;
476     for (i=start2; i<len;
477     i++)
478     debug("%s%02x",
479     i?",":"",
480     data[i]);
481     } else
482     for (i=0; i<len; i++)
483     debug("%s%02x",
484     i?",":"",
485     data[i]);
486     debug("}");
487     }
488 dpavlin 12
489     fatal(" paddr=0x%llx >= physical_max"
490     "; pc=", (long long)paddr);
491     if (cpu->is_32bit)
492     fatal("0x%08x",(int)old_pc);
493     else
494     fatal("0x%016llx",
495     (long long)old_pc);
496 dpavlin 2 symbol = get_symbol_name(
497     &cpu->machine->symbol_context,
498 dpavlin 12 old_pc, &offset);
499     fatal(" <%s> ]\n",
500     symbol? symbol : " no symbol ");
501 dpavlin 2 }
502    
503     if (cpu->machine->single_step_on_bad_addr) {
504     fatal("[ unimplemented access to "
505 dpavlin 12 "0x%llx, pc=0x",(long long)paddr);
506     if (cpu->is_32bit)
507     fatal("%08x ]\n",
508     (int)old_pc);
509     else
510     fatal("%016llx ]\n",
511     (long long)old_pc);
512 dpavlin 2 single_step = 1;
513     }
514     }
515    
516     if (writeflag == MEM_READ) {
517 dpavlin 6 #ifdef MEM_X86
518     /* Reading non-existant memory on x86: */
519     memset(data, 0xff, len);
520     #else
521 dpavlin 2 /* Return all zeroes? (Or 0xff? TODO) */
522     memset(data, 0, len);
523 dpavlin 6 #endif
524 dpavlin 2
525     #ifdef MEM_MIPS
526     /*
527     * For real data/instruction accesses, cause
528     * an exceptions on an illegal read:
529     */
530     if (cache != CACHE_NONE && cpu->machine->
531 dpavlin 6 dbe_on_nonexistant_memaccess &&
532     !no_exceptions) {
533 dpavlin 2 if (paddr >= mem->physical_max &&
534     paddr < mem->physical_max+1048576)
535     mips_cpu_exception(cpu,
536     EXCEPTION_DBE, 0, vaddr, 0,
537     0, 0, 0);
538     }
539     #endif /* MEM_MIPS */
540     }
541    
542     /* Hm? Shouldn't there be a DBE exception for
543     invalid writes as well? TODO */
544    
545     goto do_return_ok;
546     }
547     }
548    
549     #endif /* ifndef MEM_USERLAND */
550    
551    
552     /*
553     * Uncached access:
554 dpavlin 18 *
555     * 1) Translate the physical address to a host address.
556     *
557     * 2) Insert this virtual->physical->host translation into the
558     * fast translation arrays (using update_translation_table()).
559     *
560     * 3) If this was a Write, then invalidate any code translations
561     * in that page.
562 dpavlin 2 */
563     memblock = memory_paddr_to_hostaddr(mem, paddr, writeflag);
564     if (memblock == NULL) {
565     if (writeflag == MEM_READ)
566     memset(data, 0, len);
567     goto do_return_ok;
568     }
569    
570     offset = paddr & ((1 << BITS_PER_MEMBLOCK) - 1);
571    
572 dpavlin 16 if (cpu->update_translation_table != NULL && !bintrans_device_danger
573 dpavlin 18 #ifndef MEM_MIPS
574 dpavlin 20 /* && !(misc_flags & MEMORY_USER_ACCESS) */
575 dpavlin 18 #ifndef MEM_USERLAND
576     && !(ok & MEMORY_NOT_FULL_PAGE)
577     #endif
578     #endif
579 dpavlin 16 && !no_exceptions)
580 dpavlin 12 cpu->update_translation_table(cpu, vaddr & ~offset_mask,
581     memblock + (offset & ~offset_mask),
582 dpavlin 20 (misc_flags & MEMORY_USER_ACCESS) |
583 dpavlin 18 #ifndef MEM_MIPS
584     (cache == CACHE_INSTRUCTION? TLB_CODE : 0) |
585     #endif
586 dpavlin 20 #if !defined(MEM_MIPS) && !defined(MEM_USERLAND)
587 dpavlin 18 (cache == CACHE_INSTRUCTION?
588 dpavlin 20 (writeflag == MEM_WRITE? 1 : 0) : ok - 1),
589 dpavlin 2 #else
590 dpavlin 18 (writeflag == MEM_WRITE? 1 : 0),
591 dpavlin 2 #endif
592 dpavlin 12 paddr & ~offset_mask);
593 dpavlin 2
594 dpavlin 18 /* Invalidate code translations for the page we are writing to. */
595 dpavlin 20 if (writeflag == MEM_WRITE && cpu->invalidate_code_translation != NULL)
596 dpavlin 14 cpu->invalidate_code_translation(cpu, paddr, INVALIDATE_PADDR);
597    
598 dpavlin 2 if (writeflag == MEM_WRITE) {
599 dpavlin 12 /* Ugly optimization, but it works: */
600     if (len == sizeof(uint32_t) && (offset & 3)==0
601     && ((size_t)data&3)==0)
602 dpavlin 2 *(uint32_t *)(memblock + offset) = *(uint32_t *)data;
603     else if (len == sizeof(uint8_t))
604     *(uint8_t *)(memblock + offset) = *(uint8_t *)data;
605     else
606     memcpy(memblock + offset, data, len);
607     } else {
608 dpavlin 12 /* Ugly optimization, but it works: */
609     if (len == sizeof(uint32_t) && (offset & 3)==0
610     && ((size_t)data&3)==0)
611 dpavlin 2 *(uint32_t *)data = *(uint32_t *)(memblock + offset);
612     else if (len == sizeof(uint8_t))
613     *(uint8_t *)data = *(uint8_t *)(memblock + offset);
614     else
615     memcpy(data, memblock + offset, len);
616    
617 dpavlin 6 #ifdef MEM_MIPS
618 dpavlin 2 if (cache == CACHE_INSTRUCTION) {
619     cpu->cd.mips.pc_last_host_4k_page = memblock
620 dpavlin 12 + (offset & ~offset_mask);
621 dpavlin 2 if (bintrans_cached) {
622     cpu->cd.mips.pc_bintrans_host_4kpage =
623     cpu->cd.mips.pc_last_host_4k_page;
624     }
625     }
626 dpavlin 6 #endif /* MIPS */
627 dpavlin 2 }
628    
629    
630     do_return_ok:
631     return MEMORY_ACCESS_OK;
632     }
633    

  ViewVC Help
Powered by ViewVC 1.1.26