/[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 12 - (hide annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 14783 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


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 12 * $Id: memory.c,v 1.175 2005/08/14 15:47: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     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     (cpu, mem->dev_baseaddr[i] + s);
298 dpavlin 2 }
299    
300 dpavlin 12 if (cpu->machine->arch == ARCH_MIPS) {
301     /*
302     * ... and invalidate the "fast_vaddr_to_
303     * hostaddr" cache entries that contain
304     * pointers to this device: (NOTE: Device i,
305     * cache entry j)
306     */
307     for (j=0; j<N_BINTRANS_VADDR_TO_HOST; j++) {
308     if (cpu->cd.
309     mips.bintrans_data_hostpage[j] >=
310     mem->dev_dyntrans_data[i] &&
311     cpu->cd.mips.
312     bintrans_data_hostpage[j] <
313     mem->dev_dyntrans_data[i] +
314     mem->dev_length[i])
315     cpu->cd.mips.
316     bintrans_data_hostpage[j]
317     = NULL;
318     }
319 dpavlin 2 }
320     return;
321     }
322     }
323     }
324    
325    
326     /*
327     * memory_device_register_statefunction():
328     *
329     * TODO: Hm. This is semi-ugly. Should probably be rewritten/redesigned
330     * some day.
331     */
332     void memory_device_register_statefunction(
333     struct memory *mem, void *extra,
334     int (*dev_f_state)(struct cpu *,
335     struct memory *, void *extra, int wf, int nr,
336     int *type, char **namep, void **data, size_t *len))
337     {
338     int i;
339    
340     for (i=0; i<mem->n_mmapped_devices; i++)
341     if (mem->dev_extra[i] == extra) {
342     mem->dev_f_state[i] = dev_f_state;
343     return;
344     }
345    
346     printf("memory_device_register_statefunction(): "
347     "couldn't find the device\n");
348     exit(1);
349     }
350    
351    
352     /*
353     * memory_device_register():
354     *
355     * Register a (memory mapped) device by adding it to the dev_* fields of a
356     * memory struct.
357     */
358     void memory_device_register(struct memory *mem, const char *device_name,
359     uint64_t baseaddr, uint64_t len,
360     int (*f)(struct cpu *,struct memory *,uint64_t,unsigned char *,
361     size_t,int,void *),
362 dpavlin 12 void *extra, int flags, unsigned char *dyntrans_data)
363 dpavlin 2 {
364     int i;
365    
366     if (mem->n_mmapped_devices >= MAX_DEVICES) {
367     fprintf(stderr, "memory_device_register(): too many "
368     "devices registered, cannot register '%s'\n", device_name);
369     exit(1);
370     }
371    
372     /* Check for collisions: */
373     for (i=0; i<mem->n_mmapped_devices; i++) {
374     /* If we are not colliding with device i, then continue: */
375     if (baseaddr + len <= mem->dev_baseaddr[i])
376     continue;
377     if (baseaddr >= mem->dev_baseaddr[i] + mem->dev_length[i])
378     continue;
379    
380     fatal("\nWARNING! \"%s\" collides with device %i (\"%s\")!\n"
381     " Run-time behaviour will be undefined!\n\n",
382     device_name, i, mem->dev_name[i]);
383     }
384    
385     /* (40 bits of physical address is displayed) */
386     debug("device %2i at 0x%010llx: %s",
387     mem->n_mmapped_devices, (long long)baseaddr, device_name);
388    
389 dpavlin 12 if (flags & (MEM_DYNTRANS_OK | MEM_DYNTRANS_WRITE_OK)
390     && (baseaddr & mem->dev_dyntrans_alignment) != 0) {
391     fatal("\nWARNING: Device dyntrans access, but unaligned"
392 dpavlin 2 " baseaddr 0x%llx.\n", (long long)baseaddr);
393     }
394    
395 dpavlin 12 if (flags & (MEM_DYNTRANS_OK | MEM_DYNTRANS_WRITE_OK)) {
396     debug(" (dyntrans %s)",
397     (flags & MEM_DYNTRANS_WRITE_OK)? "R/W" : "R");
398 dpavlin 2 }
399     debug("\n");
400    
401     mem->dev_name[mem->n_mmapped_devices] = strdup(device_name);
402     mem->dev_baseaddr[mem->n_mmapped_devices] = baseaddr;
403     mem->dev_length[mem->n_mmapped_devices] = len;
404     mem->dev_flags[mem->n_mmapped_devices] = flags;
405 dpavlin 12 mem->dev_dyntrans_data[mem->n_mmapped_devices] = dyntrans_data;
406 dpavlin 2
407     if (mem->dev_name[mem->n_mmapped_devices] == NULL) {
408     fprintf(stderr, "out of memory\n");
409     exit(1);
410     }
411    
412 dpavlin 12 if (flags & (MEM_DYNTRANS_OK | MEM_DYNTRANS_WRITE_OK)
413     && dyntrans_data == NULL) {
414     fatal("\nERROR: Device dyntrans access, but dyntrans_data"
415     " = NULL!\n");
416     exit(1);
417     }
418    
419     if ((size_t)dyntrans_data & 7) {
420 dpavlin 2 fprintf(stderr, "memory_device_register():"
421 dpavlin 12 " dyntrans_data not aligned correctly (%p)\n",
422     dyntrans_data);
423 dpavlin 2 exit(1);
424     }
425    
426 dpavlin 12 mem->dev_dyntrans_write_low[mem->n_mmapped_devices] = (uint64_t)-1;
427     mem->dev_dyntrans_write_high[mem->n_mmapped_devices] = 0;
428 dpavlin 2 mem->dev_f[mem->n_mmapped_devices] = f;
429     mem->dev_extra[mem->n_mmapped_devices] = extra;
430     mem->n_mmapped_devices++;
431    
432     if (baseaddr < mem->mmap_dev_minaddr)
433 dpavlin 12 mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment;
434 dpavlin 2 if (baseaddr + len > mem->mmap_dev_maxaddr)
435 dpavlin 12 mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) |
436     mem->dev_dyntrans_alignment) + 1;
437 dpavlin 2 }
438    
439    
440     /*
441     * memory_device_remove():
442     *
443     * Unregister a (memory mapped) device from a memory struct.
444     */
445     void memory_device_remove(struct memory *mem, int i)
446     {
447     if (i < 0 || i >= mem->n_mmapped_devices) {
448     fatal("memory_device_remove(): invalid device number %i\n", i);
449     return;
450     }
451    
452     mem->n_mmapped_devices --;
453    
454     if (i == mem->n_mmapped_devices)
455     return;
456    
457     /*
458     * YUCK! This is ugly. TODO: fix
459     */
460    
461     memmove(&mem->dev_name[i], &mem->dev_name[i+1], sizeof(char *) *
462     (MAX_DEVICES - i - 1));
463     memmove(&mem->dev_baseaddr[i], &mem->dev_baseaddr[i+1],
464     sizeof(uint64_t) * (MAX_DEVICES - i - 1));
465     memmove(&mem->dev_length[i], &mem->dev_length[i+1], sizeof(uint64_t) *
466     (MAX_DEVICES - i - 1));
467     memmove(&mem->dev_flags[i], &mem->dev_flags[i+1], sizeof(int) *
468     (MAX_DEVICES - i - 1));
469     memmove(&mem->dev_extra[i], &mem->dev_extra[i+1], sizeof(void *) *
470     (MAX_DEVICES - i - 1));
471     memmove(&mem->dev_f[i], &mem->dev_f[i+1], sizeof(void *) *
472     (MAX_DEVICES - i - 1));
473     memmove(&mem->dev_f_state[i], &mem->dev_f_state[i+1], sizeof(void *) *
474     (MAX_DEVICES - i - 1));
475 dpavlin 12 memmove(&mem->dev_dyntrans_data[i], &mem->dev_dyntrans_data[i+1],
476 dpavlin 2 sizeof(void *) * (MAX_DEVICES - i - 1));
477 dpavlin 12 memmove(&mem->dev_dyntrans_write_low[i], &mem->dev_dyntrans_write_low
478 dpavlin 2 [i+1], sizeof(void *) * (MAX_DEVICES - i - 1));
479 dpavlin 12 memmove(&mem->dev_dyntrans_write_high[i], &mem->dev_dyntrans_write_high
480 dpavlin 2 [i+1], sizeof(void *) * (MAX_DEVICES - i - 1));
481     }
482    
483    
484     #define MEMORY_RW userland_memory_rw
485     #define MEM_USERLAND
486     #include "memory_rw.c"
487     #undef MEM_USERLAND
488     #undef MEMORY_RW
489    
490    
491     /*
492     * memory_paddr_to_hostaddr():
493     *
494     * Translate a physical address into a host address.
495     *
496     * Return value is a pointer to a host memblock, or NULL on failure.
497     * On reads, a NULL return value should be interpreted as reading all zeroes.
498     */
499     unsigned char *memory_paddr_to_hostaddr(struct memory *mem,
500     uint64_t paddr, int writeflag)
501     {
502     void **table;
503     int entry;
504     const int mask = (1 << BITS_PER_PAGETABLE) - 1;
505     const int shrcount = MAX_BITS - BITS_PER_PAGETABLE;
506    
507     table = mem->pagetable;
508     entry = (paddr >> shrcount) & mask;
509    
510 dpavlin 12 /* printf("memory_paddr_to_hostaddr(): p=%16llx w=%i => entry=0x%x\n",
511     (long long)paddr, writeflag, entry); */
512 dpavlin 2
513     if (table[entry] == NULL) {
514     size_t alloclen;
515    
516     /*
517     * Special case: reading from a nonexistant memblock
518     * returns all zeroes, and doesn't allocate anything.
519     * (If any intermediate pagetable is nonexistant, then
520     * the same thing happens):
521     */
522     if (writeflag == MEM_READ)
523     return NULL;
524    
525     /* Allocate a memblock: */
526     alloclen = 1 << BITS_PER_MEMBLOCK;
527    
528     /* printf(" allocating for entry %i, len=%i\n",
529     entry, alloclen); */
530    
531     /* Anonymous mmap() should return zero-filled memory,
532     try malloc + memset if mmap failed. */
533     table[entry] = (void *) mmap(NULL, alloclen,
534     PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
535     -1, 0);
536     if (table[entry] == NULL) {
537     table[entry] = malloc(alloclen);
538     if (table[entry] == NULL) {
539     fatal("out of memory\n");
540     exit(1);
541     }
542     memset(table[entry], 0, alloclen);
543     }
544     }
545    
546     return (unsigned char *) table[entry];
547     }
548    

  ViewVC Help
Powered by ViewVC 1.1.26