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

Contents of /trunk/src/memory.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 20 - (show 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 /*
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 * $Id: memory.c,v 1.182 2005/11/22 16:26:36 debug Exp $
29 *
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, byte_order = cpu->byte_order;
63 uint64_t x = 0;
64
65 if (len & MEM_PCI_LITTLE_ENDIAN) {
66 len &= ~MEM_PCI_LITTLE_ENDIAN;
67 byte_order = EMUL_LITTLE_ENDIAN;
68 }
69
70 /* Switch byte order for incoming data, if necessary: */
71 if (byte_order == EMUL_BIG_ENDIAN)
72 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 int i, byte_order = cpu->byte_order;
98
99 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 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 * malloc() + memset(). The returned memory block contains only zeroes.
122 */
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 struct memory *memory_new(uint64_t physical_max, int arch)
146 {
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 mem->dev_dyntrans_alignment = 4095;
171 if (arch == ARCH_ALPHA)
172 mem->dev_dyntrans_alignment = 8191;
173
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 * memory_device_dyntrans_access():
270 *
271 * Get the lowest and highest dyntrans (or bintrans) access since last time.
272 */
273 void memory_device_dyntrans_access(struct cpu *cpu, struct memory *mem,
274 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 mem->dev_dyntrans_data[i] != NULL) {
287 if (mem->dev_dyntrans_write_low[i] != (uint64_t) -1)
288 need_inval = 1;
289 if (low != NULL)
290 *low = mem->dev_dyntrans_write_low[i];
291 mem->dev_dyntrans_write_low[i] = (uint64_t) -1;
292
293 if (high != NULL)
294 *high = mem->dev_dyntrans_write_high[i];
295 mem->dev_dyntrans_write_high[i] = 0;
296
297 if (!need_inval)
298 return;
299
300 /* Invalidate any pages of this device that might
301 be in the dyntrans load/store cache, by marking
302 the pages read-only. */
303 if (cpu->invalidate_translation_caches != NULL) {
304 for (s=0; s<mem->dev_length[i];
305 s+=cpu->machine->arch_pagesize)
306 cpu->invalidate_translation_caches
307 (cpu, mem->dev_baseaddr[i] + s,
308 JUST_MARK_AS_NON_WRITABLE
309 | INVALIDATE_PADDR);
310 }
311
312 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 }
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 void *extra, int flags, unsigned char *dyntrans_data)
375 {
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 if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)
402 && (baseaddr & mem->dev_dyntrans_alignment) != 0) {
403 fatal("\nWARNING: Device dyntrans access, but unaligned"
404 " baseaddr 0x%llx.\n", (long long)baseaddr);
405 }
406
407 if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)) {
408 debug(" (dyntrans %s)",
409 (flags & DM_DYNTRANS_WRITE_OK)? "R/W" : "R");
410 }
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 mem->dev_endaddr[mem->n_mmapped_devices] = baseaddr + len;
416 mem->dev_length[mem->n_mmapped_devices] = len;
417 mem->dev_flags[mem->n_mmapped_devices] = flags;
418 mem->dev_dyntrans_data[mem->n_mmapped_devices] = dyntrans_data;
419
420 if (mem->dev_name[mem->n_mmapped_devices] == NULL) {
421 fprintf(stderr, "out of memory\n");
422 exit(1);
423 }
424
425 if (flags & (DM_DYNTRANS_OK | DM_DYNTRANS_WRITE_OK)
426 && !(flags & DM_EMULATED_RAM) && dyntrans_data == NULL) {
427 fatal("\nERROR: Device dyntrans access, but dyntrans_data"
428 " = NULL!\n");
429 exit(1);
430 }
431
432 if ((size_t)dyntrans_data & (sizeof(void *) - 1)) {
433 fprintf(stderr, "memory_device_register():"
434 " dyntrans_data not aligned correctly (%p)\n",
435 dyntrans_data);
436 exit(1);
437 }
438
439 mem->dev_dyntrans_write_low[mem->n_mmapped_devices] = (uint64_t)-1;
440 mem->dev_dyntrans_write_high[mem->n_mmapped_devices] = 0;
441 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 mem->mmap_dev_minaddr = baseaddr & ~mem->dev_dyntrans_alignment;
447 if (baseaddr + len > mem->mmap_dev_maxaddr)
448 mem->mmap_dev_maxaddr = (((baseaddr + len) - 1) |
449 mem->dev_dyntrans_alignment) + 1;
450 }
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 memmove(&mem->dev_dyntrans_data[i], &mem->dev_dyntrans_data[i+1],
489 sizeof(void *) * (MAX_DEVICES - i - 1));
490 memmove(&mem->dev_dyntrans_write_low[i], &mem->dev_dyntrans_write_low
491 [i+1], sizeof(void *) * (MAX_DEVICES - i - 1));
492 memmove(&mem->dev_dyntrans_write_high[i], &mem->dev_dyntrans_write_high
493 [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 /* printf("memory_paddr_to_hostaddr(): p=%16llx w=%i => entry=0x%x\n",
524 (long long)paddr, writeflag, entry); */
525
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