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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 14 - (hide annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 14819 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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 14 * $Id: memory.c,v 1.176 2005/08/28 20:16:23 debug Exp $
29 dpavlin 2 *
30     * Functions for handling the memory of an emulated machine.
31     */
32    
33     #include <stdio.h>
34     #include <stdlib.h>
35     #include <string.h>
36     #include <sys/types.h>
37     #include <sys/mman.h>
38    
39     #include "bintrans.h"
40     #include "cop0.h"
41     #include "cpu.h"
42     #include "machine.h"
43     #include "memory.h"
44     #include "mips_cpu_types.h"
45     #include "misc.h"
46    
47    
48     extern int quiet_mode;
49     extern volatile int single_step;
50    
51    
52     /*
53     * memory_readmax64():
54     *
55     * Read at most 64 bits of data from a buffer. Length is given by
56     * len, and the byte order by cpu->byte_order.
57     *
58     * This function should not be called with cpu == NULL.
59     */
60     uint64_t memory_readmax64(struct cpu *cpu, unsigned char *buf, int len)
61     {
62     int i;
63     uint64_t x = 0;
64    
65     /* Switch byte order for incoming data, if necessary: */
66     if (cpu->byte_order == EMUL_BIG_ENDIAN)
67     for (i=0; i<len; i++) {
68     x <<= 8;
69     x |= buf[i];
70     }
71     else
72     for (i=len-1; i>=0; i--) {
73     x <<= 8;
74     x |= buf[i];
75     }
76    
77     return x;
78     }
79    
80    
81     /*
82     * memory_writemax64():
83     *
84     * Write at most 64 bits of data to a buffer. Length is given by
85     * len, and the byte order by cpu->byte_order.
86     *
87     * This function should not be called with cpu == NULL.
88     */
89     void memory_writemax64(struct cpu *cpu, unsigned char *buf, int len,
90     uint64_t data)
91     {
92     int i;
93    
94     if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
95     for (i=0; i<len; i++) {
96     buf[i] = data & 255;
97     data >>= 8;
98     }
99     else
100     for (i=0; i<len; i++) {
101     buf[len - 1 - i] = data & 255;
102     data >>= 8;
103     }
104     }
105    
106    
107     /*
108     * zeroed_alloc():
109     *
110     * Allocates a block of memory using mmap(), and if that fails, try
111 dpavlin 12 * malloc() + memset(). The returned memory block contains only zeroes.
112 dpavlin 2 */
113     void *zeroed_alloc(size_t s)
114     {
115     void *p = mmap(NULL, s, PROT_READ | PROT_WRITE,
116     MAP_ANON | MAP_PRIVATE, -1, 0);
117     if (p == NULL) {
118     p = malloc(s);
119     if (p == NULL) {
120     fprintf(stderr, "out of memory\n");
121     exit(1);
122     }
123     memset(p, 0, s);
124     }
125     return p;
126     }
127    
128    
129     /*
130     * memory_new():
131     *
132     * This function creates a new memory object. An emulated machine needs one
133     * of these.
134     */
135 dpavlin 12 struct memory *memory_new(uint64_t physical_max, int arch)
136 dpavlin 2 {
137     struct memory *mem;
138     int bits_per_pagetable = BITS_PER_PAGETABLE;
139     int bits_per_memblock = BITS_PER_MEMBLOCK;
140     int entries_per_pagetable = 1 << BITS_PER_PAGETABLE;
141     int max_bits = MAX_BITS;
142     size_t s;
143    
144     mem = malloc(sizeof(struct memory));
145     if (mem == NULL) {
146     fprintf(stderr, "out of memory\n");
147     exit(1);
148     }
149    
150     memset(mem, 0, sizeof(struct memory));
151    
152     /* Check bits_per_pagetable and bits_per_memblock for sanity: */
153     if (bits_per_pagetable + bits_per_memblock != max_bits) {
154     fprintf(stderr, "memory_new(): bits_per_pagetable and "
155     "bits_per_memblock mismatch\n");
156     exit(1);
157     }
158    
159     mem->physical_max = physical_max;
160 dpavlin 12 mem->dev_dyntrans_alignment = 4095;
161     if (arch == ARCH_ALPHA)
162     mem->dev_dyntrans_alignment = 8191;
163 dpavlin 2
164     s = entries_per_pagetable * sizeof(void *);
165    
166     mem->pagetable = (unsigned char *) mmap(NULL, s,
167     PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
168     if (mem->pagetable == NULL) {
169     mem->pagetable = malloc(s);
170     if (mem->pagetable == NULL) {
171     fprintf(stderr, "out of memory\n");
172     exit(1);
173     }
174     memset(mem->pagetable, 0, s);
175     }
176    
177     mem->mmap_dev_minaddr = 0xffffffffffffffffULL;
178     mem->mmap_dev_maxaddr = 0;
179    
180     return mem;
181     }
182    
183    
184     /*
185     * memory_points_to_string():
186     *
187     * Returns 1 if there's something string-like at addr, otherwise 0.
188     */
189     int memory_points_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr,
190     int min_string_length)
191     {
192     int cur_length = 0;
193     unsigned char c;
194    
195     for (;;) {
196     c = '\0';
197     cpu->memory_rw(cpu, mem, addr+cur_length,
198     &c, sizeof(c), MEM_READ, CACHE_NONE | NO_EXCEPTIONS);
199     if (c=='\n' || c=='\t' || c=='\r' || (c>=' ' && c<127)) {
200     cur_length ++;
201     if (cur_length >= min_string_length)
202     return 1;
203     } else {
204     if (cur_length >= min_string_length)
205     return 1;
206     else
207     return 0;
208     }
209     }
210     }
211    
212    
213     /*
214     * memory_conv_to_string():
215     *
216     * Convert virtual memory contents to a string, placing it in a
217     * buffer provided by the caller.
218     */
219     char *memory_conv_to_string(struct cpu *cpu, struct memory *mem, uint64_t addr,
220     char *buf, int bufsize)
221     {
222     int len = 0;
223     int output_index = 0;
224     unsigned char c, p='\0';
225    
226     while (output_index < bufsize-1) {
227     c = '\0';
228     cpu->memory_rw(cpu, mem, addr+len, &c, sizeof(c), MEM_READ,
229     CACHE_NONE | NO_EXCEPTIONS);
230     buf[output_index] = c;
231     if (c>=' ' && c<127) {
232     len ++;
233     output_index ++;
234     } else if (c=='\n' || c=='\r' || c=='\t') {
235     len ++;
236     buf[output_index] = '\\';
237     output_index ++;
238     switch (c) {
239     case '\n': p = 'n'; break;
240     case '\r': p = 'r'; break;
241     case '\t': p = 't'; break;
242     }
243     if (output_index < bufsize-1) {
244     buf[output_index] = p;
245     output_index ++;
246     }
247     } else {
248     buf[output_index] = '\0';
249     return buf;
250     }
251     }
252    
253     buf[bufsize-1] = '\0';
254     return buf;
255     }
256    
257    
258     /*
259 dpavlin 12 * memory_device_dyntrans_access():
260 dpavlin 2 *
261 dpavlin 12 * Get the lowest and highest dyntrans (or bintrans) access since last time.
262 dpavlin 2 */
263 dpavlin 12 void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem,
264 dpavlin 2 void *extra, uint64_t *low, uint64_t *high)
265     {
266     int i, j;
267     size_t s;
268     int need_inval = 0;
269    
270     /* TODO: This is O(n), so it might be good to rewrite it some day.
271     For now, it will be enough, as long as this function is not
272     called too often. */
273    
274     for (i=0; i<mem->n_mmapped_devices; i++) {
275     if (mem->dev_extra[i] == extra &&
276 dpavlin 12 mem->dev_dyntrans_data[i] != NULL) {
277     if (mem->dev_dyntrans_write_low[i] != (uint64_t) -1)
278 dpavlin 2 need_inval = 1;
279     if (low != NULL)
280 dpavlin 12 *low = mem->dev_dyntrans_write_low[i];
281     mem->dev_dyntrans_write_low[i] = (uint64_t) -1;
282 dpavlin 2
283     if (high != NULL)
284 dpavlin 12 *high = mem->dev_dyntrans_write_high[i];
285     mem->dev_dyntrans_write_high[i] = 0;
286 dpavlin 2
287     if (!need_inval)
288     return;
289    
290     /* Invalidate any pages of this device that might
291 dpavlin 12 be in the dyntrans load/store cache, by marking
292 dpavlin 2 the pages read-only. */
293 dpavlin 12 if (cpu->invalidate_translation_caches_paddr != NULL) {
294     for (s=0; s<mem->dev_length[i];
295     s+=cpu->machine->arch_pagesize)
296     cpu->invalidate_translation_caches_paddr
297 dpavlin 14 (cpu, mem->dev_baseaddr[i] + s,
298     JUST_MARK_AS_NON_WRITABLE);
299 dpavlin 2 }
300    
301 dpavlin 12 if (cpu->machine->arch == ARCH_MIPS) {
302     /*
303     * ... and invalidate the "fast_vaddr_to_
304     * hostaddr" cache entries that contain
305     * pointers to this device: (NOTE: Device i,
306     * cache entry j)
307     */
308     for (j=0; j<N_BINTRANS_VADDR_TO_HOST; j++) {
309     if (cpu->cd.
310     mips.bintrans_data_hostpage[j] >=
311     mem->dev_dyntrans_data[i] &&
312     cpu->cd.mips.
313     bintrans_data_hostpage[j] <
314     mem->dev_dyntrans_data[i] +
315     mem->dev_length[i])
316     cpu->cd.mips.
317     bintrans_data_hostpage[j]
318     = NULL;
319     }
320 dpavlin 2 }
321     return;
322     }
323     }
324     }
325    
326    
327     /*
328     * memory_device_register_statefunction():
329     *
330     * TODO: Hm. This is semi-ugly. Should probably be rewritten/redesigned
331     * some day.
332     */
333     void memory_device_register_statefunction(
334     struct memory *mem, void *extra,
335     int (*dev_f_state)(struct cpu *,
336     struct memory *, void *extra, int wf, int nr,
337     int *type, char **namep, void **data, size_t *len))
338     {
339     int i;
340    
341     for (i=0; i<mem->n_mmapped_devices; i++)
342     if (mem->dev_extra[i] == extra) {
343     mem->dev_f_state[i] = dev_f_state;
344     return;
345     }
346    
347     printf("memory_device_register_statefunction(): "
348     "couldn't find the device\n");
349     exit(1);
350     }
351    
352    
353     /*
354     * memory_device_register():
355     *
356     * Register a (memory mapped) device by adding it to the dev_* fields of a
357     * memory struct.
358     */
359     void memory_device_register(struct memory *mem, const char *device_name,
360     uint64_t baseaddr, uint64_t len,
361     int (*f)(struct cpu *,struct memory *,uint64_t,unsigned char *,
362     size_t,int,void *),
363 dpavlin 12 void *extra, int flags, unsigned char *dyntrans_data)
364 dpavlin 2 {
365     int i;
366    
367     if (mem->n_mmapped_devices >= MAX_DEVICES) {
368     fprintf(stderr, "memory_device_register(): too many "
369     "devices registered, cannot register '%s'\n", device_name);
370     exit(1);
371     }
372    
373     /* Check for collisions: */
374     for (i=0; i<mem->n_mmapped_devices; i++) {
375     /* If we are not colliding with device i, then continue: */
376     if (baseaddr + len <= mem->dev_baseaddr[i])
377     continue;
378     if (baseaddr >= mem->dev_baseaddr[i] + mem->dev_length[i])
379     continue;
380    
381     fatal("\nWARNING! \"%s\" collides with device %i (\"%s\")!\n"
382     " Run-time behaviour will be undefined!\n\n",
383     device_name, i, mem->dev_name[i]);
384     }
385    
386     /* (40 bits of physical address is displayed) */
387     debug("device %2i at 0x%010llx: %s",
388     mem->n_mmapped_devices, (long long)baseaddr, device_name);
389    
390 dpavlin 12 if (flags & (MEM_DYNTRANS_OK | MEM_DYNTRANS_WRITE_OK)
391     && (baseaddr & mem->dev_dyntrans_alignment) != 0) {
392     fatal("\nWARNING: Device dyntrans access, but unaligned"
393 dpavlin 2 " baseaddr 0x%llx.\n", (long long)baseaddr);
394     }
395    
396 dpavlin 12 if (flags & (MEM_DYNTRANS_OK | MEM_DYNTRANS_WRITE_OK)) {
397     debug(" (dyntrans %s)",
398     (flags & MEM_DYNTRANS_WRITE_OK)? "R/W" : "R");
399 dpavlin 2 }
400     debug("\n");
401    
402     mem->dev_name[mem->n_mmapped_devices] = strdup(device_name);
403     mem->dev_baseaddr[mem->n_mmapped_devices] = baseaddr;
404     mem->dev_length[mem->n_mmapped_devices] = len;
405     mem->dev_flags[mem->n_mmapped_devices] = flags;
406 dpavlin 12 mem->dev_dyntrans_data[mem->n_mmapped_devices] = dyntrans_data;
407 dpavlin 2
408     if (mem->dev_name[mem->n_mmapped_devices] == NULL) {
409     fprintf(stderr, "out of memory\n");
410     exit(1);
411     }
412    
413 dpavlin 12 if (flags & (MEM_DYNTRANS_OK | MEM_DYNTRANS_WRITE_OK)
414     && dyntrans_data == NULL) {
415     fatal("\nERROR: Device dyntrans access, but dyntrans_data"
416     " = NULL!\n");
417     exit(1);
418     }
419    
420     if ((size_t)dyntrans_data & 7) {
421 dpavlin 2 fprintf(stderr, "memory_device_register():"
422 dpavlin 12 " dyntrans_data not aligned correctly (%p)\n",
423     dyntrans_data);
424 dpavlin 2 exit(1);
425     }
426    
427 dpavlin 12 mem->dev_dyntrans_write_low[mem->n_mmapped_devices] = (uint64_t)-1;
428     mem->dev_dyntrans_write_high[mem->n_mmapped_devices] = 0;
429 dpavlin 2 mem->dev_f[mem->n_mmapped_devices] = f;
430     mem->dev_extra[mem->n_mmapped_devices] = extra;
431     mem->n_mmapped_devices++;
432    
433     if (baseaddr < mem->mmap_dev_minaddr)
434 dpavlin 12 mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment;
435 dpavlin 2 if (baseaddr + len > mem->mmap_dev_maxaddr)
436 dpavlin 12 mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) |
437     mem->dev_dyntrans_alignment) + 1;
438 dpavlin 2 }
439    
440    
441     /*
442     * memory_device_remove():
443     *
444     * Unregister a (memory mapped) device from a memory struct.
445     */
446     void memory_device_remove(struct memory *mem, int i)
447     {
448     if (i < 0 || i >= mem->n_mmapped_devices) {
449     fatal("memory_device_remove(): invalid device number %i\n", i);
450     return;
451     }
452    
453     mem->n_mmapped_devices --;
454    
455     if (i == mem->n_mmapped_devices)
456     return;
457    
458     /*
459     * YUCK! This is ugly. TODO: fix
460     */
461    
462     memmove(&mem->dev_name[i], &mem->dev_name[i+1], sizeof(char *) *
463     (MAX_DEVICES - i - 1));
464     memmove(&mem->dev_baseaddr[i], &mem->dev_baseaddr[i+1],
465     sizeof(uint64_t) * (MAX_DEVICES - i - 1));
466     memmove(&mem->dev_length[i], &mem->dev_length[i+1], sizeof(uint64_t) *
467     (MAX_DEVICES - i - 1));
468     memmove(&mem->dev_flags[i], &mem->dev_flags[i+1], sizeof(int) *
469     (MAX_DEVICES - i - 1));
470     memmove(&mem->dev_extra[i], &mem->dev_extra[i+1], sizeof(void *) *
471     (MAX_DEVICES - i - 1));
472     memmove(&mem->dev_f[i], &mem->dev_f[i+1], sizeof(void *) *
473     (MAX_DEVICES - i - 1));
474     memmove(&mem->dev_f_state[i], &mem->dev_f_state[i+1], sizeof(void *) *
475     (MAX_DEVICES - i - 1));
476 dpavlin 12 memmove(&mem->dev_dyntrans_data[i], &mem->dev_dyntrans_data[i+1],
477 dpavlin 2 sizeof(void *) * (MAX_DEVICES - i - 1));
478 dpavlin 12 memmove(&mem->dev_dyntrans_write_low[i], &mem->dev_dyntrans_write_low
479 dpavlin 2 [i+1], sizeof(void *) * (MAX_DEVICES - i - 1));
480 dpavlin 12 memmove(&mem->dev_dyntrans_write_high[i], &mem->dev_dyntrans_write_high
481 dpavlin 2 [i+1], sizeof(void *) * (MAX_DEVICES - i - 1));
482     }
483    
484    
485     #define MEMORY_RW userland_memory_rw
486     #define MEM_USERLAND
487     #include "memory_rw.c"
488     #undef MEM_USERLAND
489     #undef MEMORY_RW
490    
491    
492     /*
493     * memory_paddr_to_hostaddr():
494     *
495     * Translate a physical address into a host address.
496     *
497     * Return value is a pointer to a host memblock, or NULL on failure.
498     * On reads, a NULL return value should be interpreted as reading all zeroes.
499     */
500     unsigned char *memory_paddr_to_hostaddr(struct memory *mem,
501     uint64_t paddr, int writeflag)
502     {
503     void **table;
504     int entry;
505     const int mask = (1 << BITS_PER_PAGETABLE) - 1;
506     const int shrcount = MAX_BITS - BITS_PER_PAGETABLE;
507    
508     table = mem->pagetable;
509     entry = (paddr >> shrcount) & mask;
510    
511 dpavlin 12 /* printf("memory_paddr_to_hostaddr(): p=%16llx w=%i => entry=0x%x\n",
512     (long long)paddr, writeflag, entry); */
513 dpavlin 2
514     if (table[entry] == NULL) {
515     size_t alloclen;
516    
517     /*
518     * Special case: reading from a nonexistant memblock
519     * returns all zeroes, and doesn't allocate anything.
520     * (If any intermediate pagetable is nonexistant, then
521     * the same thing happens):
522     */
523     if (writeflag == MEM_READ)
524     return NULL;
525    
526     /* Allocate a memblock: */
527     alloclen = 1 << BITS_PER_MEMBLOCK;
528    
529     /* printf(" allocating for entry %i, len=%i\n",
530     entry, alloclen); */
531    
532     /* Anonymous mmap() should return zero-filled memory,
533     try malloc + memset if mmap failed. */
534     table[entry] = (void *) mmap(NULL, alloclen,
535     PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
536     -1, 0);
537     if (table[entry] == NULL) {
538     table[entry] = malloc(alloclen);
539     if (table[entry] == NULL) {
540     fatal("out of memory\n");
541     exit(1);
542     }
543     memset(table[entry], 0, alloclen);
544     }
545     }
546    
547     return (unsigned char *) table[entry];
548     }
549    

  ViewVC Help
Powered by ViewVC 1.1.26