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

  ViewVC Help
Powered by ViewVC 1.1.26