/[gxemul]/upstream/0.4.4/src/useremul.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 /upstream/0.4.4/src/useremul.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
Original Path: trunk/src/useremul.c
File MIME type: text/plain
File size: 43617 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) 2004-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: useremul.c,v 1.66 2005/11/11 13:23:15 debug Exp $
29 dpavlin 2 *
30     * Userland (syscall) emulation.
31     *
32     * TODO:
33     *
34 dpavlin 14 * environment passing for most emulation modes
35 dpavlin 2 *
36 dpavlin 14 * implement more syscalls
37     *
38 dpavlin 2 * 32-bit vs 64-bit problems? MIPS n32, o32, n64?
39     *
40     * Dynamic ELFs?
41     *
42     * Try to prefix "/emul/mips/" or similar to all filenames,
43     * and only if that fails, try the given filename
44     *
45     * Automagic errno translation?
46     *
47     * Memory allocation? mmap etc.
48     *
49     * File descriptor (0,1,2) assumptions?
50     *
51     *
52     * This module needs more cleanup.
53     * -------------------------------
54     *
55     *
56     * NOTE: This module (useremul.c) is just a quick hack to see if
57     * userland emulation works at all.
58     */
59    
60     #include <errno.h>
61     #include <fcntl.h>
62     #include <stdio.h>
63     #include <stdlib.h>
64     #include <stdarg.h>
65     #include <string.h>
66     #include <unistd.h>
67     #include <sys/time.h>
68     #include <sys/stat.h>
69     #include <sys/socket.h>
70 dpavlin 12 #include <sys/resource.h>
71 dpavlin 2 #include <time.h>
72    
73     #include "cpu.h"
74     #include "cpu_mips.h"
75     #include "emul.h"
76     #include "machine.h"
77     #include "memory.h"
78     #include "misc.h"
79     #include "syscall_linux_ppc.h"
80     #include "syscall_netbsd.h"
81     #include "syscall_ultrix.h"
82     #include "sysctl_netbsd.h"
83    
84     struct syscall_emul {
85     char *name;
86     int arch;
87     char *cpu_name;
88     void (*f)(struct cpu *, uint32_t);
89     void (*setup)(struct cpu *, int, char **);
90    
91     struct syscall_emul *next;
92     };
93    
94     static struct syscall_emul *first_syscall_emul;
95    
96     /* Max length of strings passed using syscall parameters: */
97     #define MAXLEN 8192
98    
99    
100     /*
101     * useremul_setup():
102     *
103     * Set up an emulated environment suitable for running userland code. The
104     * program should already have been loaded into memory when this function
105     * is called.
106     */
107     void useremul_setup(struct cpu *cpu, int argc, char **host_argv)
108     {
109     struct syscall_emul *sep;
110    
111     sep = first_syscall_emul;
112    
113     while (sep != NULL) {
114     if (strcasecmp(cpu->machine->userland_emul, sep->name) == 0) {
115     sep->setup(cpu, argc, host_argv);
116     return;
117     }
118     sep = sep->next;
119     }
120    
121     fatal("useremul_setup(): internal error, unimplemented emulation?\n");
122     exit(1);
123     }
124    
125    
126     /*
127     * useremul__freebsd_setup():
128     *
129     * Set up an emulated userland environment suitable for running FreeBSD
130     * binaries.
131     */
132     void useremul__freebsd_setup(struct cpu *cpu, int argc, char **host_argv)
133     {
134     debug("useremul__freebsd_setup(): TODO\n");
135    
136 dpavlin 12 switch (cpu->machine->arch) {
137     case ARCH_ALPHA:
138     /* According to FreeBSD's /usr/src/lib/csu/alpha/crt1.c: */
139     /* a0 = char **ap */
140     /* a1 = void (*cleanup)(void) from shared loader */
141     /* a2 = struct Struct_Obj_Entry *obj from shared loader */
142     /* a3 = struct ps_strings *ps_strings */
143     cpu->cd.alpha.r[ALPHA_A0] = 0;
144     cpu->cd.alpha.r[ALPHA_A1] = 0;
145     cpu->cd.alpha.r[ALPHA_A2] = 0;
146     cpu->cd.alpha.r[ALPHA_A3] = 0;
147    
148     /* What is a good stack pointer? TODO */
149     cpu->cd.alpha.r[ALPHA_SP] = 0x120000000ULL +
150     1048576 * cpu->machine->physical_ram_in_mb - 1024;
151     break;
152     default:
153 dpavlin 2 fatal("non-Alpha not yet implemented for freebsd emul.\n");
154     exit(1);
155     }
156     }
157    
158    
159     /*
160     * useremul__linux_setup():
161     *
162     * Set up an emulated userland environment suitable for running Linux
163     * binaries.
164     */
165     void useremul__linux_setup(struct cpu *cpu, int argc, char **host_argv)
166     {
167     debug("useremul__linux_setup(): TODO\n");
168    
169     if (cpu->machine->arch != ARCH_PPC) {
170     fatal("non-PPC not yet implemented for linux emul.\n");
171     exit(1);
172     }
173    
174     /* What is a good stack pointer? TODO */
175     cpu->cd.ppc.gpr[1] = 0x7ffff000ULL;
176     }
177    
178    
179     /*
180     * useremul__netbsd_setup():
181     *
182     * Set up an emulated userland environment suitable for running NetBSD
183     * binaries.
184     */
185     void useremul__netbsd_setup(struct cpu *cpu, int argc, char **host_argv)
186     {
187     uint64_t stack_top = 0x7fff0000;
188     uint64_t stacksize = 8 * 1048576;
189     uint64_t stack_margin = 16384;
190     uint64_t cur_argv;
191     int i, i2;
192     int envc = 1;
193    
194     switch (cpu->machine->arch) {
195     case ARCH_MIPS:
196     /* See netbsd/sys/src/arch/mips/mips_machdep.c:setregs() */
197     cpu->cd.mips.gpr[MIPS_GPR_A0] = stack_top - stack_margin;
198     cpu->cd.mips.gpr[25] = cpu->pc; /* reg. t9 */
199    
200     /* The userland stack: */
201     cpu->cd.mips.gpr[MIPS_GPR_SP] = stack_top - stack_margin;
202     add_symbol_name(&cpu->machine->symbol_context,
203 dpavlin 12 stack_top - stacksize, stacksize, "userstack", 0, 0);
204 dpavlin 2
205     /* Stack contents: (TODO: is this correct?) */
206     store_32bit_word(cpu, stack_top - stack_margin, argc);
207    
208     cur_argv = stack_top - stack_margin + 128 + (argc + envc)
209     * sizeof(uint32_t);
210     for (i=0; i<argc; i++) {
211     debug("adding argv[%i]: '%s'\n", i, host_argv[i]);
212    
213     store_32bit_word(cpu, stack_top - stack_margin +
214     4 + i*sizeof(uint32_t), cur_argv);
215     store_string(cpu, cur_argv, host_argv[i]);
216     cur_argv += strlen(host_argv[i]) + 1;
217     }
218    
219     /* Store a NULL value between the args and the environment
220     strings: */
221     store_32bit_word(cpu, stack_top - stack_margin +
222     4 + i*sizeof(uint32_t), 0); i++;
223    
224     /* TODO: get environment strings from somewhere */
225    
226     /* Store all environment strings: */
227     for (i2 = 0; i2 < envc; i2 ++) {
228     store_32bit_word(cpu, stack_top - stack_margin + 4
229     + (i+i2)*sizeof(uint32_t), cur_argv);
230     store_string(cpu, cur_argv, "DISPLAY=localhost:0.0");
231     cur_argv += strlen("DISPLAY=localhost:0.0") + 1;
232     }
233     break;
234    
235 dpavlin 14 case ARCH_ALPHA:
236     debug("useremul__netbsd_setup(): ALPHA: TODO\n");
237     break;
238    
239 dpavlin 12 case ARCH_ARM:
240     debug("useremul__netbsd_setup(): ARM: TODO\n");
241     break;
242    
243 dpavlin 2 case ARCH_PPC:
244 dpavlin 4 debug("useremul__netbsd_setup(): PPC: TODO\n");
245 dpavlin 2
246     /* What is a good stack pointer? TODO */
247     cpu->cd.ppc.gpr[1] = 0x7ffff000ULL;
248    
249     break;
250    
251 dpavlin 4 case ARCH_X86:
252     debug("useremul__netbsd_setup(): X86: TODO\n");
253    
254     break;
255    
256 dpavlin 2 default:
257     fatal("useremul__netbsd_setup(): unimplemented arch\n");
258     exit(1);
259     }
260     }
261    
262    
263     /*
264     * useremul__ultrix_setup():
265     *
266     * Set up an emulated userland environment suitable for running Ultrix
267     * binaries.
268     */
269     void useremul__ultrix_setup(struct cpu *cpu, int argc, char **host_argv)
270     {
271     uint64_t stack_top = 0x7fff0000;
272     uint64_t stacksize = 8 * 1048576;
273     uint64_t stack_margin = 16384;
274     uint64_t cur_argv;
275     int i, i2;
276     int envc = 1;
277    
278     /* TODO: is this correct? */
279     cpu->cd.mips.gpr[MIPS_GPR_A0] = stack_top - stack_margin;
280     cpu->cd.mips.gpr[25] = cpu->pc; /* reg. t9 */
281    
282     /* The userland stack: */
283     cpu->cd.mips.gpr[MIPS_GPR_SP] = stack_top - stack_margin;
284     add_symbol_name(&cpu->machine->symbol_context,
285 dpavlin 12 stack_top - stacksize, stacksize, "userstack", 0, 0);
286 dpavlin 2
287     /* Stack contents: (TODO: is this correct?) */
288     store_32bit_word(cpu, stack_top - stack_margin, argc);
289    
290     cur_argv = stack_top - stack_margin + 128 +
291     (argc + envc) * sizeof(uint32_t);
292     for (i=0; i<argc; i++) {
293     debug("adding argv[%i]: '%s'\n", i, host_argv[i]);
294    
295     store_32bit_word(cpu, stack_top - stack_margin +
296     4 + i*sizeof(uint32_t), cur_argv);
297     store_string(cpu, cur_argv, host_argv[i]);
298     cur_argv += strlen(host_argv[i]) + 1;
299     }
300    
301     /* Store a NULL value between the args and the environment strings: */
302     store_32bit_word(cpu, stack_top - stack_margin
303     + 4 + i*sizeof(uint32_t), 0); i++;
304    
305     /* TODO: get environment strings from somewhere */
306    
307     /* Store all environment strings: */
308     for (i2 = 0; i2 < envc; i2 ++) {
309     store_32bit_word(cpu, stack_top - stack_margin + 4 +
310     (i+i2)*sizeof(uint32_t), cur_argv);
311     store_string(cpu, cur_argv, "DISPLAY=localhost:0.0");
312     cur_argv += strlen("DISPLAY=localhost:0.0") + 1;
313     }
314     }
315    
316    
317     /*
318     * get_userland_string():
319     *
320     * This can be used to retrieve strings, for example filenames,
321     * from the emulated memory.
322     *
323     * NOTE: This function returns a pointer to a malloced buffer. It is up to
324     * the caller to use free().
325     */
326     static unsigned char *get_userland_string(struct cpu *cpu, uint64_t baseaddr)
327     {
328     unsigned char *charbuf;
329     int i, len = 16384;
330    
331     charbuf = malloc(len);
332     if (charbuf == NULL) {
333     fprintf(stderr, "get_userland_string(): out of memory (trying"
334     " to allocate %i bytes)\n", len);
335     exit(1);
336     }
337    
338     /* TODO: address validity check */
339    
340     for (i=0; i<len; i++) {
341     cpu->memory_rw(cpu, cpu->mem, baseaddr+i, charbuf+i,
342     1, MEM_READ, CACHE_DATA);
343     if (charbuf[i] == '\0')
344     break;
345     }
346    
347     charbuf[MAXLEN-1] = 0;
348     return charbuf;
349     }
350    
351    
352     /*
353     * get_userland_buf():
354     *
355     * This can be used to retrieve buffers, for example inet_addr, from
356     * emulated memory.
357     *
358     * NOTE: This function returns a pointer to a malloced buffer. It is up to
359     * the caller to use free().
360     *
361     * TODO: combine this with get_userland_string() in some way
362     */
363     static unsigned char *get_userland_buf(struct cpu *cpu,
364 dpavlin 12 uint64_t baseaddr, uint64_t len)
365 dpavlin 2 {
366     unsigned char *charbuf;
367 dpavlin 12 ssize_t i;
368 dpavlin 2
369     charbuf = malloc(len);
370     if (charbuf == NULL) {
371     fprintf(stderr, "get_userland_buf(): out of memory (trying"
372 dpavlin 12 " to allocate %lli bytes)\n", (long long)len);
373 dpavlin 2 exit(1);
374     }
375    
376     /* TODO: address validity check */
377     for (i=0; i<len; i++) {
378     cpu->memory_rw(cpu, cpu->mem, baseaddr+i, charbuf+i, 1,
379     MEM_READ, CACHE_DATA);
380     /* debug(" %02x", charbuf[i]); */
381     }
382     debug("\n");
383    
384     return charbuf;
385     }
386    
387    
388     /*
389     * useremul_syscall():
390     *
391     * Handle userland syscalls. This function is called whenever a userland
392     * process runs a 'syscall' instruction. The code argument is the code
393     * embedded into the syscall instruction, if any. (This 'code' value is not
394     * necessarily used by specific emulations.)
395     */
396     void useremul_syscall(struct cpu *cpu, uint32_t code)
397     {
398     if (cpu->useremul_syscall == NULL) {
399     fatal("useremul_syscall(): cpu->useremul_syscall == NULL\n");
400     } else
401     cpu->useremul_syscall(cpu, code);
402     }
403    
404    
405 dpavlin 12 /*****************************************************************************/
406    
407    
408 dpavlin 2 /*
409 dpavlin 12 * useremul_exit():
410     */
411     int useremul_exit(struct cpu *cpu, uint64_t arg0)
412     {
413     debug("[ exit(%i) ]\n", (int)arg0);
414     cpu->running = 0;
415     cpu->machine->exit_without_entering_debugger = 1;
416     return 0;
417     }
418    
419    
420     /*
421     * useremul_write():
422     */
423     int64_t useremul_write(struct cpu *cpu, int64_t *errnop,
424     uint64_t arg0, uint64_t arg1, uint64_t arg2)
425     {
426     int64_t res = 0;
427     *errnop = 0;
428     debug("[ write(%i,0x%llx,%lli) ]\n",
429     (int)arg0, (long long)arg1, (long long)arg2);
430     if (arg2 != 0) {
431     unsigned char *cp = get_userland_buf(cpu, arg1, arg2);
432     res = write(arg0, cp, arg2);
433     if (res < 0)
434     *errnop = errno;
435     free(cp);
436     }
437     return res;
438     }
439    
440    
441     /*
442     * useremul_break():
443     */
444     int64_t useremul_break(struct cpu *cpu, uint64_t arg0)
445     {
446     debug("[ break(0x%llx): TODO ]\n", (long long)arg0);
447    
448     /* TODO */
449     return 0;
450     }
451    
452    
453     /*
454     * useremul_getpid():
455     */
456     int64_t useremul_getpid(struct cpu *cpu)
457     {
458     int64_t pid = getpid();
459     debug("[ getpid(): %lli ]\n", (long long)pid);
460     return pid;
461     }
462    
463    
464     /*
465     * useremul_getuid():
466     */
467     int64_t useremul_getuid(struct cpu *cpu)
468     {
469     int64_t uid = getuid();
470     debug("[ getuid(): %lli ]\n", (long long)uid);
471     return uid;
472     }
473    
474    
475     /*
476     * useremul_getegid():
477     */
478     int64_t useremul_getegid(struct cpu *cpu)
479     {
480     int64_t egid = getegid();
481     debug("[ getegid(): %lli ]\n", (long long)egid);
482     return egid;
483     }
484    
485    
486     /*
487     * useremul_getgid():
488     */
489     int64_t useremul_getgid(struct cpu *cpu)
490     {
491     int64_t gid = getgid();
492     debug("[ getgid(): %lli ]\n", (long long)gid);
493     return gid;
494     }
495    
496    
497     /*
498     * useremul_sync():
499     */
500     int useremul_sync(struct cpu *cpu)
501     {
502     debug("[ sync() ]\n");
503     sync();
504     return 0;
505     }
506    
507    
508     /*
509     * useremul_readlink():
510     */
511     int64_t useremul_readlink(struct cpu *cpu, int64_t *errnop,
512     uint64_t arg0, uint64_t arg1, int64_t arg2)
513     {
514     int64_t res = 0;
515     unsigned char *charbuf = get_userland_string(cpu, arg0);
516     unsigned char *buf2;
517    
518     debug("[ readlink(\"%s\",0x%llx,%lli) ]\n",
519     charbuf, (long long)arg1, (long long)arg2);
520     if (arg2 == 0 || arg2 > 150000) {
521     fprintf(stderr, "[ useremul_readlink(): TODO ]\n");
522     exit(1);
523     }
524    
525     buf2 = malloc(arg2);
526     if (buf2 == NULL) {
527     fprintf(stderr, "[ useremul_readlink(): out of memory ]\n");
528     exit(1);
529     }
530     res = readlink((char *)charbuf, (char *)buf2, arg2);
531     buf2[arg2-1] = '\0';
532     if (res < 0)
533     *errnop = errno;
534     else
535     store_string(cpu, arg1, (char *)buf2);
536     free(buf2);
537     free(charbuf);
538     return res;
539     }
540    
541    
542     /*
543     * useremul_getrusage():
544     */
545     int64_t useremul_getrusage(struct cpu *cpu, int64_t *errnop,
546     uint64_t arg0, uint64_t arg1)
547     {
548     int64_t res;
549     struct rusage rusage;
550     debug("[ getrusage(%i,0x%llx) ]\n", (int)arg0, (long long)arg1);
551     res = getrusage(arg0, &rusage);
552    
553     fatal("TODO: convert rusage into emulated memory!\n");
554     store_64bit_word(cpu, arg1 + 0, rusage.ru_utime.tv_sec);
555     store_64bit_word(cpu, arg1 + 8, rusage.ru_utime.tv_usec);
556     store_64bit_word(cpu, arg1 + 16, rusage.ru_stime.tv_sec);
557     store_64bit_word(cpu, arg1 + 24, rusage.ru_stime.tv_usec);
558    
559     return res;
560     }
561    
562    
563     /*
564     * useremul_fstat():
565     */
566     int64_t useremul_fstat(struct cpu *cpu, int64_t *errnop,
567     int64_t arg0, uint64_t arg1)
568     {
569     int64_t res;
570     struct stat sb;
571     debug("[ fstat(%i,0x%llx) ]\n", (int)arg0, (long long)arg1);
572     res = fstat(arg0, &sb);
573     if (res < 0)
574     *errnop = errno;
575     else {
576     fatal("TODO: convert sb into emulated memory!\n");
577    
578     /* NOTE: FreeBSD/alpha only */
579    
580     store_32bit_word(cpu, arg1 + 0, sb.st_dev);
581     store_32bit_word(cpu, arg1 + 4, sb.st_ino);
582     /* store_16bit_word(cpu, arg1 + 8, sb.st_mode);
583     */ store_16bit_word(cpu, arg1 + 10, sb.st_nlink);
584     store_32bit_word(cpu, arg1 + 12, sb.st_uid);
585     store_32bit_word(cpu, arg1 + 16, sb.st_gid);
586     store_32bit_word(cpu, arg1 + 20, sb.st_rdev);
587     #if 0
588     store_64bit_word(cpu, arg1 + 24, sb.st_atimespec.tv_sec);
589     store_64bit_word(cpu, arg1 + 32, sb.st_atimespec.tv_nsec);
590     store_64bit_word(cpu, arg1 + 40, sb.st_mtimespec.tv_sec);
591     store_64bit_word(cpu, arg1 + 48, sb.st_mtimespec.tv_nsec);
592     store_64bit_word(cpu, arg1 + 56, sb.st_ctimespec.tv_sec);
593     store_64bit_word(cpu, arg1 + 64, sb.st_ctimespec.tv_nsec);
594    
595     store_64bit_word(cpu, arg1 + 72, sb.st_size);
596     store_64bit_word(cpu, arg1 + 80, sb.st_blocks);
597     store_64bit_word(cpu, arg1 + 88, sb.st_blksize);
598     store_64bit_word(cpu, arg1 + 92, sb.st_flags);
599     store_64bit_word(cpu, arg1 + 96, sb.st_gen);
600     #endif
601     }
602     return res;
603     }
604    
605    
606     /*
607     * useremul_mmap():
608     */
609     int64_t useremul_mmap(struct cpu *cpu, int64_t *errnop,
610     uint64_t arg0, int64_t arg1, int64_t arg2,
611     int64_t arg3, int64_t arg4, uint64_t arg5)
612     {
613     int64_t res = 0;
614    
615     /* arg0..5: addr, len, prot, flags, fd, offset */
616     debug("[ mmap(0x%llx,%lli,%i,%i,%i,%lli) ]\n",
617     (long long)arg0, (long long)arg1,
618     (int)arg2, (int)arg3, (int)arg4, (long long)arg5);
619    
620     if (arg4 != -1) {
621     fatal("[ useremul_mmap(): fd != -1: TODO ]\n");
622     cpu->running = 0;
623     return 0;
624     }
625    
626     /* Anonymous allocation. */
627     if (arg0 != 0) {
628     fatal("[ useremul_mmap(): addr != 0: TODO ]\n");
629     cpu->running = 0;
630     return 0;
631     }
632    
633     fatal("[ useremul_mmap(): TODO ]\n");
634    
635     res = 0x18000000ULL;
636    
637     return res;
638     }
639    
640    
641     /*****************************************************************************/
642    
643    
644     /*
645 dpavlin 2 * useremul__freebsd():
646     *
647 dpavlin 12 * FreeBSD/Alpha syscall emulation.
648 dpavlin 2 *
649     * TODO: How to make this work nicely with non-Alpha archs.
650     */
651     static void useremul__freebsd(struct cpu *cpu, uint32_t code)
652     {
653     int nr;
654 dpavlin 12 int64_t res = 0, err = 0;
655     uint64_t arg0, arg1, arg2, arg3, arg4, arg5;
656 dpavlin 2
657 dpavlin 12 nr = cpu->cd.alpha.r[ALPHA_V0];
658     arg0 = cpu->cd.alpha.r[ALPHA_A0];
659     arg1 = cpu->cd.alpha.r[ALPHA_A1];
660     arg2 = cpu->cd.alpha.r[ALPHA_A2];
661     arg3 = cpu->cd.alpha.r[ALPHA_A3];
662     arg4 = cpu->cd.alpha.r[ALPHA_A4];
663     arg5 = cpu->cd.alpha.r[ALPHA_A5];
664 dpavlin 2
665 dpavlin 12 if (nr == 198) {
666     /* ___syscall */
667     nr = arg0;
668     arg0 = arg1;
669     arg1 = arg2;
670     arg2 = arg3;
671     arg3 = arg4;
672     arg4 = arg5;
673     /* TODO: stack arguments */
674     }
675    
676 dpavlin 2 switch (nr) {
677    
678 dpavlin 12 case 1: res = useremul_exit(cpu, arg0);
679 dpavlin 2 break;
680    
681 dpavlin 12 case 4: res = useremul_write(cpu, &err, arg0, arg1, arg2);
682 dpavlin 2 break;
683    
684 dpavlin 12 case 17:res = useremul_break(cpu, arg0);
685     break;
686    
687     case 20:res = useremul_getpid(cpu);
688     break;
689    
690     case 24:res = useremul_getuid(cpu);
691     break;
692    
693     case 43:res = useremul_getegid(cpu);
694     break;
695    
696     case 47:res = useremul_getgid(cpu);
697     break;
698    
699     case 58:res = useremul_readlink(cpu, &err, arg0, arg1, arg2);
700     break;
701    
702     case 117:res = useremul_getrusage(cpu, &err, arg0, arg1);
703     break;
704    
705     case 189:res = useremul_fstat(cpu, &err, arg0, arg1);
706     break;
707    
708     case 197:res = useremul_mmap(cpu, &err, arg0, arg1, arg2, arg3,
709     arg4, arg5);
710     break;
711    
712     default:fatal("useremul__freebsd(): syscall %i not yet "
713     "implemented\n", nr);
714 dpavlin 2 cpu->running = 0;
715     }
716 dpavlin 12
717     if (err) {
718     cpu->cd.alpha.r[ALPHA_A3] = 1;
719     cpu->cd.alpha.r[ALPHA_V0] = err;
720     } else {
721     cpu->cd.alpha.r[ALPHA_A3] = 0;
722     cpu->cd.alpha.r[ALPHA_V0] = res;
723     }
724 dpavlin 2 }
725    
726    
727     /*
728     * useremul__linux():
729     *
730     * Linux syscall emulation.
731     *
732     * TODO: How to make this work nicely with non-PPC archs.
733     */
734     static void useremul__linux(struct cpu *cpu, uint32_t code)
735     {
736     int nr;
737 dpavlin 12 int64_t res = 0, err = 0;
738 dpavlin 2 uint64_t arg0, arg1, arg2, arg3;
739    
740     if (code != 0) {
741     fatal("useremul__linux(): code %i: TODO\n", (int)code);
742     exit(1);
743     }
744    
745     nr = cpu->cd.ppc.gpr[0];
746     arg0 = cpu->cd.ppc.gpr[3];
747     arg1 = cpu->cd.ppc.gpr[4];
748     arg2 = cpu->cd.ppc.gpr[5];
749     arg3 = cpu->cd.ppc.gpr[6];
750    
751     switch (nr) {
752    
753     case LINUX_PPC_SYS_exit:
754 dpavlin 12 res = useremul_exit(cpu, arg0);
755 dpavlin 2 break;
756    
757     case LINUX_PPC_SYS_write:
758 dpavlin 12 res = useremul_write(cpu, &err, arg0, arg1, arg2);
759 dpavlin 2 break;
760    
761     default:
762     fatal("useremul__linux(): syscall %i not yet implemented\n",
763     nr);
764     cpu->running = 0;
765     }
766 dpavlin 12
767     /* return res: TODO */
768 dpavlin 2 }
769    
770    
771     /*
772     * useremul__netbsd():
773     *
774     * NetBSD syscall emulation.
775     */
776     static void useremul__netbsd(struct cpu *cpu, uint32_t code)
777     {
778     int error_flag = 0, result_high_set = 0;
779     uint64_t arg0=0,arg1=0,arg2=0,arg3=0,stack0=0,stack1=0,stack2=0;
780     int sysnr = 0;
781 dpavlin 12 int64_t error_code = 0;
782 dpavlin 2 uint64_t result_low = 0;
783     uint64_t result_high = 0;
784     struct timeval tv;
785     struct timezone tz;
786     int descr;
787     uint64_t length, mipsbuf, flags;
788     unsigned char *charbuf;
789     uint32_t sysctl_name, sysctl_namelen, sysctl_oldp,
790     sysctl_oldlenp, sysctl_newp, sysctl_newlen;
791     uint32_t name0, name1, name2, name3;
792    
793     switch (cpu->machine->arch) {
794     case ARCH_MIPS:
795     sysnr = cpu->cd.mips.gpr[MIPS_GPR_V0];
796     if (sysnr == NETBSD_SYS___syscall) {
797     sysnr = cpu->cd.mips.gpr[MIPS_GPR_A0] +
798     (cpu->cd.mips.gpr[MIPS_GPR_A1] << 32);
799     arg0 = cpu->cd.mips.gpr[MIPS_GPR_A2];
800     arg1 = cpu->cd.mips.gpr[MIPS_GPR_A3];
801     /* TODO: stack arguments? Are these correct? */
802     arg2 = load_32bit_word(cpu,
803     cpu->cd.mips.gpr[MIPS_GPR_SP] + 8);
804     arg3 = load_32bit_word(cpu,
805     cpu->cd.mips.gpr[MIPS_GPR_SP] + 16);
806     stack0 = load_32bit_word(cpu,
807     cpu->cd.mips.gpr[MIPS_GPR_SP] + 24);
808     stack1 = load_32bit_word(cpu,
809     cpu->cd.mips.gpr[MIPS_GPR_SP] + 32);
810     stack2 = load_32bit_word(cpu,
811     cpu->cd.mips.gpr[MIPS_GPR_SP] + 40);
812     } else {
813     arg0 = cpu->cd.mips.gpr[MIPS_GPR_A0];
814     arg1 = cpu->cd.mips.gpr[MIPS_GPR_A1];
815     arg2 = cpu->cd.mips.gpr[MIPS_GPR_A2];
816     arg3 = cpu->cd.mips.gpr[MIPS_GPR_A3];
817     /* TODO: stack arguments? Are these correct? */
818     stack0 = load_32bit_word(cpu,
819     cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
820     stack1 = load_32bit_word(cpu,
821     cpu->cd.mips.gpr[MIPS_GPR_SP] + 8);
822     stack2 = load_32bit_word(cpu,
823     cpu->cd.mips.gpr[MIPS_GPR_SP] + 12);
824     }
825     break;
826    
827     case ARCH_PPC:
828     sysnr = cpu->cd.ppc.gpr[0];
829     arg0 = cpu->cd.ppc.gpr[3];
830     arg1 = cpu->cd.ppc.gpr[4];
831     arg2 = cpu->cd.ppc.gpr[5];
832     arg3 = cpu->cd.ppc.gpr[6];
833     /* TODO: More arguments? Stack arguments? */
834     break;
835 dpavlin 14
836     case ARCH_ARM:
837     sysnr = code & 0xfffff;
838     arg0 = cpu->cd.arm.r[0];
839     arg1 = cpu->cd.arm.r[1];
840     arg2 = cpu->cd.arm.r[2];
841     arg3 = cpu->cd.arm.r[3];
842     /* TODO: More arguments? Stack arguments? */
843     break;
844    
845     default:fatal("netbsd syscall for this arch: TODO\n");
846     exit(1);
847 dpavlin 2 }
848    
849     /*
850 dpavlin 18 * NOTE/TODO: The following code should not be CPU arch dependent!
851 dpavlin 2 */
852    
853     switch (sysnr) {
854    
855     case NETBSD_SYS_exit:
856     debug("[ exit(%i) ]\n", (int)arg0);
857     cpu->running = 0;
858     cpu->machine->exit_without_entering_debugger = 1;
859     break;
860    
861     case NETBSD_SYS_read:
862     debug("[ read(%i,0x%llx,%lli) ]\n",
863     (int)arg0, (long long)arg1, (long long)arg2);
864    
865     if (arg2 != 0) {
866     charbuf = malloc(arg2);
867     if (charbuf == NULL) {
868     fprintf(stderr, "out of memory in "
869     "useremul__netbsd()\n");
870     exit(1);
871     }
872     result_low = read(arg0, charbuf, arg2);
873     if ((int64_t)result_low < 0) {
874     error_code = errno;
875     error_flag = 1;
876     }
877    
878     /* TODO: address validity check */
879     cpu->memory_rw(cpu, cpu->mem, arg1, charbuf,
880     arg2, MEM_WRITE, CACHE_DATA);
881     free(charbuf);
882     }
883     break;
884    
885     case NETBSD_SYS_write:
886     descr = arg0;
887     mipsbuf = arg1;
888     length = arg2;
889     debug("[ write(%i,0x%llx,%lli) ]\n",
890     (int)descr, (long long)mipsbuf, (long long)length);
891     if (length != 0) {
892     charbuf = malloc(length);
893     if (charbuf == NULL) {
894     fprintf(stderr, "out of memory in "
895     "useremul__netbsd()\n");
896     exit(1);
897     }
898     /* TODO: address validity check */
899     cpu->memory_rw(cpu, cpu->mem, mipsbuf, charbuf,
900     length, MEM_READ, CACHE_DATA);
901     result_low = write(descr, charbuf, length);
902     if ((int64_t)result_low < 0) {
903     error_code = errno;
904     error_flag = 1;
905     }
906     free(charbuf);
907     }
908     break;
909    
910     case NETBSD_SYS_open:
911     charbuf = get_userland_string(cpu, arg0);
912     debug("[ open(\"%s\", 0x%llx, 0x%llx) ]\n",
913     charbuf, (long long)arg1, (long long)arg2);
914     result_low = open((char *)charbuf, arg1, arg2);
915     if ((int64_t)result_low < 0) {
916     error_flag = 1;
917     error_code = errno;
918     }
919     free(charbuf);
920     break;
921    
922     case NETBSD_SYS_close:
923     descr = arg0;
924     debug("[ close(%i) ]\n", (int)descr);
925     error_code = close(descr);
926     if (error_code != 0)
927     error_flag = 1;
928     break;
929    
930     case NETBSD_SYS_access:
931     charbuf = get_userland_string(cpu, arg0);
932     debug("[ access(\"%s\", 0x%llx) ]\n",
933     charbuf, (long long) arg1);
934     result_low = access((char *)charbuf, arg1);
935     if (result_low != 0) {
936     error_flag = 1;
937     error_code = errno;
938     }
939     free(charbuf);
940     break;
941    
942     case NETBSD_SYS_getuid:
943 dpavlin 12 result_low = useremul_getuid(cpu);
944 dpavlin 2 break;
945    
946     case NETBSD_SYS_geteuid:
947     debug("[ geteuid() ]\n");
948     result_low = geteuid();
949     break;
950    
951     case NETBSD_SYS_getgid:
952     debug("[ getgid() ]\n");
953     result_low = getgid();
954     break;
955    
956     case NETBSD_SYS_getegid:
957     debug("[ getegid() ]\n");
958     result_low = getegid();
959     break;
960    
961     case NETBSD_SYS_getfsstat:
962     mipsbuf = arg0;
963     length = arg1;
964     flags = arg2;
965     debug("[ getfsstat(0x%llx,%lli,0x%llx) ]\n",
966     (long long)mipsbuf, (long long)length,
967     (long long)flags);
968    
969     result_low = 0; /* nr of mounted filesystems,
970     for now (TODO) */
971    
972     /* Fill in the struct statfs buffer at arg0...
973     copy data from the host's getfsstat(). TODO */
974     #if 1
975     result_low = 1;
976     store_32bit_word(cpu, mipsbuf + 0, 0); /* f_spare2 */
977     store_32bit_word(cpu, mipsbuf + 4, 1024); /* f_bsize */
978     store_32bit_word(cpu, mipsbuf + 8, 65536); /* f_iosize */
979     store_32bit_word(cpu, mipsbuf + 12, 100); /* f_blocks */
980     store_32bit_word(cpu, mipsbuf + 16, 50); /* f_bfree */
981     store_32bit_word(cpu, mipsbuf + 20, 10); /* f_bavail */
982     store_32bit_word(cpu, mipsbuf + 24, 50); /* f_files */
983     store_32bit_word(cpu, mipsbuf + 28, 25); /* f_ffree */
984     store_32bit_word(cpu, mipsbuf + 28, 0x1234); /* f_fsid */
985     store_32bit_word(cpu, mipsbuf + 32, 0); /* f_owner */
986     store_32bit_word(cpu, mipsbuf + 36, 0); /* f_type */
987     store_32bit_word(cpu, mipsbuf + 40, 0); /* f_flags */
988     store_32bit_word(cpu, mipsbuf + 44, 0); /* f_fspare[0] */
989     store_32bit_word(cpu, mipsbuf + 48, 0); /* f_fspare[1] */
990     store_string(cpu, mipsbuf + 52, "ffs"); /* f_typename */
991     #define MFSNAMELEN 16
992     #define MNAMELEN 90
993     store_string(cpu, mipsbuf + 52 + MFSNAMELEN, "/");
994     /* f_mntonname */
995     store_string(cpu, mipsbuf + 52 + MFSNAMELEN + MNAMELEN, "ffs");
996     /* f_mntfromname */
997     #endif
998     break;
999    
1000     case NETBSD_SYS_break:
1001 dpavlin 12 useremul_break(cpu, arg0);
1002 dpavlin 2 break;
1003    
1004     case NETBSD_SYS_readlink:
1005 dpavlin 12 result_low = useremul_readlink(cpu, &error_code,
1006     arg0, arg1, arg2);
1007 dpavlin 2 break;
1008    
1009     case NETBSD_SYS_sync:
1010 dpavlin 12 useremul_sync(cpu);
1011 dpavlin 2 break;
1012    
1013     case NETBSD_SYS_gettimeofday:
1014     debug("[ gettimeofday(0x%llx,0x%llx) ]\n",
1015     (long long)arg0, (long long)arg1);
1016     result_low = gettimeofday(&tv, &tz);
1017     if (result_low) {
1018     error_flag = 1;
1019     error_code = errno;
1020     } else {
1021     if (arg0 != 0) {
1022     /* Store tv.tv_sec and tv.tv_usec as
1023     'long' (32-bit) values: */
1024     store_32bit_word(cpu, arg0 + 0,
1025     tv.tv_sec);
1026     store_32bit_word(cpu, arg0 + 4,
1027     tv.tv_usec);
1028     }
1029     if (arg1 != 0) {
1030     /* Store tz.tz_minuteswest and
1031     tz.tz_dsttime as 'long'
1032     (32-bit) values: */
1033     store_32bit_word(cpu, arg1 + 0,
1034     tz.tz_minuteswest);
1035     store_32bit_word(cpu, arg1 + 4,
1036     tz.tz_dsttime);
1037     }
1038     }
1039     break;
1040    
1041     case NETBSD_SYS_mmap:
1042     debug("[ mmap(0x%x,%i,%i,%i,%i,0x%llx): TODO ]\n",
1043     arg0, arg1, arg2, arg3, stack0, (long long)stack1);
1044    
1045     if ((int32_t)stack0 == -1) {
1046     /*
1047     * Anonymous allocation:
1048     *
1049     * TODO: Fix this!!!
1050     *
1051     * This quick hack simply allocates anonymous
1052     * mmap memory approximately below the stack.
1053     * This will probably not work with dynamically
1054     * loaded libraries and such.
1055     */
1056     static uint32_t mmap_anon_ptr = 0x70000000;
1057     mmap_anon_ptr -= arg1;
1058     /* round down to page boundary: */
1059     mmap_anon_ptr &= ~4095;
1060     debug("ANON: %i bytes at 0x%08x (TODO: not "
1061     "working yet?)\n", (int)arg1,
1062     mmap_anon_ptr);
1063     result_low = mmap_anon_ptr;
1064     } else {
1065     /* Return NULL for now */
1066     }
1067     break;
1068    
1069     case NETBSD_SYS_dup:
1070     debug("[ dup(%i) ]\n", (int)arg0);
1071     result_low = dup(arg0);
1072     if ((int64_t)result_low < 0) {
1073     error_code = errno;
1074     error_flag = 1;
1075     }
1076     break;
1077    
1078     case NETBSD_SYS_socket:
1079     debug("[ socket(%i,%i,%i) ]\n",
1080     (int)arg0, (int)arg1, (int)arg2);
1081     result_low = socket(arg0,arg1,arg2);
1082     if ((int64_t)result_low < 0) {
1083     error_code = errno;
1084     error_flag = 1;
1085     }
1086     break;
1087    
1088     case NETBSD_SYS_issetugid:
1089     debug("[ issetugid() ]\n");
1090     /* TODO: actually call the real issetugid? */
1091     break;
1092    
1093     case NETBSD_SYS_nanosleep:
1094     debug("[ nanosleep(0x%llx,0x%llx) ]\n",
1095     (long long)arg0, (long long)arg1);
1096    
1097     if (arg0 != 0) {
1098     uint32_t sec = load_32bit_word(cpu, arg0 + 0);
1099     uint32_t nsec = load_32bit_word(cpu, arg0 + 4);
1100     struct timespec ts;
1101     ts.tv_sec = sec;
1102     ts.tv_nsec = nsec;
1103     result_low = nanosleep(&ts, NULL);
1104     if (result_low)
1105     fprintf(stderr, "netbsd emulation "
1106     "nanosleep() failed\n");
1107     /* TODO: arg1 */
1108     } else {
1109     error_flag = 1;
1110     error_code = 14; /* EFAULT */
1111     }
1112     break;
1113    
1114     case NETBSD_SYS___fstat13:
1115     debug("[ __fstat13(%lli,0x%llx): TODO ]\n",
1116     (long long)arg0, (long long)arg1);
1117     error_flag = 1;
1118     error_code = 9; /* EBADF */
1119     break;
1120    
1121     case NETBSD_SYS___getcwd:
1122     debug("[ __getcwd(0x%llx,%lli): TODO ]\n",
1123     (long long)arg0, (long long)arg1);
1124     if (arg1 != 0 && arg1 < 500000) {
1125     char *buf = malloc(arg1);
1126     unsigned int i;
1127    
1128     getcwd(buf, arg1);
1129    
1130     /* zero-terminate in host's space: */
1131     buf[arg1 - 1] = 0;
1132    
1133     for (i = 0; i<arg1 && i < arg1; i++)
1134     cpu->memory_rw(cpu, cpu->mem, arg0 + i,
1135     (unsigned char *)&buf[i], 1,
1136     MEM_WRITE, CACHE_NONE);
1137    
1138     /* zero-terminate in emulated space: */
1139     cpu->memory_rw(cpu, cpu->mem, arg0 + arg1-1,
1140     (unsigned char *)&buf[arg1 - 1],
1141     1, MEM_WRITE, CACHE_NONE);
1142    
1143     free(buf);
1144     }
1145     result_low = arg0;
1146     break;
1147    
1148     case NETBSD_SYS___sigaction14:
1149     debug("[ __sigaction14(%lli,0x%llx,0x%llx): TODO ]\n",
1150     (long long)arg0, (long long)arg1, (long long)arg2);
1151     error_flag = 1;
1152     error_code = 9; /* EBADF */
1153     break;
1154    
1155     case NETBSD_SYS___sysctl:
1156     sysctl_name = arg0;
1157     sysctl_namelen = arg1;
1158     sysctl_oldp = arg2;
1159     sysctl_oldlenp = arg3;
1160     sysctl_newp = load_32bit_word(cpu,
1161     cpu->cd.mips.gpr[MIPS_GPR_SP]);
1162     /* TODO: +4 and +8 ?? */
1163     sysctl_newlen = load_32bit_word(cpu,
1164     cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
1165     debug("[ __sysctl(");
1166    
1167     name0 = load_32bit_word(cpu, sysctl_name + 0);
1168     name1 = load_32bit_word(cpu, sysctl_name + 4);
1169     name2 = load_32bit_word(cpu, sysctl_name + 8);
1170     name3 = load_32bit_word(cpu, sysctl_name + 12);
1171     debug("name (@ 0x%08x) = %i, %i, %i, %i) ]\n",
1172     sysctl_name, name0, name1, name2, name3);
1173    
1174     if (name0 == CTL_KERN && name1 == KERN_HOSTNAME) {
1175     char hname[256];
1176     hname[0] = '\0';
1177     gethostname(hname, sizeof(hname));
1178     hname[sizeof(hname)-1] = '\0';
1179     if (sysctl_oldp != 0)
1180     store_string(cpu, sysctl_oldp, hname);
1181     if (sysctl_oldlenp != 0)
1182     store_32bit_word(cpu, sysctl_oldlenp,
1183     strlen(hname));
1184     } else if (name0 == CTL_HW && name1 == HW_PAGESIZE) {
1185     if (sysctl_oldp != 0)
1186     store_32bit_word(cpu,
1187     sysctl_oldp, 4096);
1188     if (sysctl_oldlenp != 0)
1189     store_32bit_word(cpu,
1190     sysctl_oldlenp, sizeof(uint32_t));
1191     } else {
1192     error_flag = 1;
1193     error_code = 2; /* ENOENT */
1194     }
1195     break;
1196    
1197     default:
1198     fatal("[ UNIMPLEMENTED netbsd syscall %i ]\n", sysnr);
1199     error_flag = 1;
1200     error_code = 78; /* ENOSYS */
1201     }
1202    
1203    
1204     switch (cpu->machine->arch) {
1205 dpavlin 14 case ARCH_ARM:
1206     /* NetBSD/arm return values: */
1207     cpu->cd.arm.r[0] = result_low;
1208     cpu->cd.arm.cpsr &= ~ARM_FLAG_C;
1209     if (error_flag) {
1210     cpu->cd.arm.cpsr |= ARM_FLAG_C;
1211     cpu->cd.arm.r[0] = error_code;
1212     }
1213     if (result_high_set)
1214     cpu->cd.arm.r[1] = result_high;
1215 dpavlin 20 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1216 dpavlin 14 break;
1217 dpavlin 2 case ARCH_MIPS:
1218     /*
1219     * NetBSD/mips return values:
1220     *
1221     * a3 is 0 if the syscall was ok, otherwise 1.
1222     * v0 (and sometimes v1) contain the result value.
1223     */
1224     cpu->cd.mips.gpr[MIPS_GPR_A3] = error_flag;
1225     if (error_flag)
1226     cpu->cd.mips.gpr[MIPS_GPR_V0] = error_code;
1227     else
1228     cpu->cd.mips.gpr[MIPS_GPR_V0] = result_low;
1229    
1230     if (result_high_set)
1231     cpu->cd.mips.gpr[MIPS_GPR_V1] = result_high;
1232     break;
1233     case ARCH_PPC:
1234     /*
1235     * NetBSD/powerpc return values:
1236     *
1237     * TODO
1238     */
1239     cpu->cd.ppc.gpr[3] = result_low;
1240    
1241     if (result_high_set)
1242     cpu->cd.ppc.gpr[4] = result_high;
1243     break;
1244     }
1245     }
1246    
1247    
1248     /*
1249     * useremul__ultrix():
1250     *
1251     * Ultrix syscall emulation.
1252     */
1253     static void useremul__ultrix(struct cpu *cpu, uint32_t code)
1254     {
1255     int error_flag = 0, result_high_set = 0;
1256     uint64_t arg0,arg1,arg2,arg3,stack0=0,stack1=0,stack2;
1257     int sysnr = 0;
1258 dpavlin 12 int64_t error_code = 0;
1259 dpavlin 2 uint64_t result_low = 0;
1260     uint64_t result_high = 0;
1261     struct timeval tv;
1262     struct timezone tz;
1263     int descr;
1264     uint64_t length, mipsbuf;
1265     unsigned char *charbuf;
1266    
1267     /*
1268     * Ultrix/pmax gets the syscall number in register v0,
1269     * and syscall arguments in registers a0, a1, ...
1270     *
1271     * TODO: If there is a __syscall-like syscall (as in NetBSD)
1272     * then 64-bit args may be passed in two registers or something...
1273     * If so, then copy from the section above (NetBSD).
1274     */
1275     sysnr = cpu->cd.mips.gpr[MIPS_GPR_V0];
1276    
1277     arg0 = cpu->cd.mips.gpr[MIPS_GPR_A0];
1278     arg1 = cpu->cd.mips.gpr[MIPS_GPR_A1];
1279     arg2 = cpu->cd.mips.gpr[MIPS_GPR_A2];
1280     arg3 = cpu->cd.mips.gpr[MIPS_GPR_A3];
1281     /* TODO: stack arguments? Are these correct? */
1282     stack0 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 0);
1283     stack1 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
1284     stack2 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 8);
1285    
1286     switch (sysnr) {
1287    
1288     case ULTRIX_SYS_exit:
1289     debug("[ exit(%i) ]\n", (int)arg0);
1290     cpu->running = 0;
1291     cpu->machine->exit_without_entering_debugger = 1;
1292     break;
1293    
1294     case ULTRIX_SYS_read:
1295     debug("[ read(%i,0x%llx,%lli) ]\n",
1296     (int)arg0, (long long)arg1, (long long)arg2);
1297    
1298     if (arg2 != 0) {
1299     charbuf = malloc(arg2);
1300     if (charbuf == NULL) {
1301     fprintf(stderr, "out of memory in "
1302     "useremul__ultrix()\n");
1303     exit(1);
1304     }
1305    
1306     result_low = read(arg0, charbuf, arg2);
1307     if ((int64_t)result_low < 0) {
1308     error_code = errno;
1309     error_flag = 1;
1310     }
1311    
1312     /* TODO: address validity check */
1313     cpu->memory_rw(cpu, cpu->mem, arg1, charbuf,
1314     arg2, MEM_WRITE, CACHE_DATA);
1315    
1316     free(charbuf);
1317     }
1318     break;
1319    
1320     case ULTRIX_SYS_write:
1321     descr = arg0;
1322     mipsbuf = arg1;
1323     length = arg2;
1324     debug("[ write(%i,0x%llx,%lli) ]\n",
1325     (int)descr, (long long)mipsbuf, (long long)length);
1326    
1327     if (length != 0) {
1328     charbuf = malloc(length);
1329     if (charbuf == NULL) {
1330     fprintf(stderr, "out of memory in "
1331     "useremul__ultrix()\n");
1332     exit(1);
1333     }
1334    
1335     /* TODO: address validity check */
1336     cpu->memory_rw(cpu, cpu->mem, mipsbuf, charbuf,
1337     length, MEM_READ, CACHE_DATA);
1338    
1339     result_low = write(descr, charbuf, length);
1340     if ((int64_t)result_low < 0) {
1341     error_code = errno;
1342     error_flag = 1;
1343     }
1344     free(charbuf);
1345     }
1346     break;
1347    
1348     case ULTRIX_SYS_open:
1349     charbuf = get_userland_string(cpu, arg0);
1350     debug("[ open(\"%s\", 0x%llx, 0x%llx) ]\n",
1351     charbuf, (long long)arg1, (long long)arg2);
1352    
1353     result_low = open((char *)charbuf, arg1, arg2);
1354     if ((int64_t)result_low < 0) {
1355     error_flag = 1;
1356     error_code = errno;
1357     }
1358     free(charbuf);
1359     break;
1360    
1361     case ULTRIX_SYS_close:
1362     descr = arg0;
1363     debug("[ close(%i) ]\n", (int)descr);
1364    
1365     /* Special case because some Ultrix programs tend
1366     to close low descriptors: */
1367     if (descr <= 2) {
1368     error_flag = 1;
1369     error_code = 2; /* TODO: Ultrix ENOENT error code */
1370     break;
1371     }
1372    
1373     error_code = close(descr);
1374     if (error_code != 0)
1375     error_flag = 1;
1376     break;
1377    
1378     case ULTRIX_SYS_break:
1379 dpavlin 12 useremul_break(cpu, arg0);
1380 dpavlin 2 break;
1381    
1382     case ULTRIX_SYS_sync:
1383 dpavlin 12 useremul_sync(cpu);
1384 dpavlin 2 break;
1385    
1386     case ULTRIX_SYS_getuid:
1387 dpavlin 12 result_low = useremul_getuid(cpu);
1388 dpavlin 2 break;
1389    
1390     case ULTRIX_SYS_getgid:
1391     debug("[ getgid() ]\n");
1392     result_low = getgid();
1393     break;
1394    
1395     case ULTRIX_SYS_dup:
1396     debug("[ dup(%i) ]\n", (int)arg0);
1397     result_low = dup(arg0);
1398     if ((int64_t)result_low < 0) {
1399     error_code = errno;
1400     error_flag = 1;
1401     }
1402     break;
1403    
1404     case ULTRIX_SYS_socket:
1405     debug("[ socket(%i,%i,%i) ]\n",
1406     (int)arg0, (int)arg1, (int)arg2);
1407     result_low = socket(arg0,arg1,arg2);
1408     if ((int64_t)result_low < 0) {
1409     error_code = errno;
1410     error_flag = 1;
1411     }
1412     break;
1413    
1414     case ULTRIX_SYS_select:
1415     debug("[ select(%i,0x%x,0x%x,0x%x,0x%x): TODO ]\n",
1416     (int)arg0, (int)arg1, (int)arg2, (int)arg3, (int)stack0);
1417    
1418     /* TODO */
1419     {
1420     fd_set fdset;
1421     FD_SET(3, &fdset);
1422     result_low = select(4, &fdset, NULL, NULL, NULL);
1423     }
1424     break;
1425    
1426     case ULTRIX_SYS_setsockopt:
1427     debug("[ setsockopt(%i,%i,%i,0x%x,%i): TODO ]\n",
1428     (int)arg0, (int)arg1, (int)arg2, (int)arg3, (int)stack0);
1429     /* TODO: len is not 4, len is stack0? */
1430     charbuf = get_userland_buf(cpu, arg3, 4);
1431     /* TODO: endianness of charbuf, etc */
1432     result_low = setsockopt(arg0, arg1, arg2, (void *)charbuf, 4);
1433     if ((int64_t)result_low < 0) {
1434     error_code = errno;
1435     error_flag = 1;
1436     }
1437     free(charbuf);
1438     printf("setsockopt!!!! res = %i error=%i\n",
1439     (int)result_low, (int)error_code);
1440     break;
1441    
1442     case ULTRIX_SYS_connect:
1443     debug("[ connect(%i,0x%x,%i) ]\n",
1444     (int)arg0, (int)arg1, (int)arg2);
1445     charbuf = get_userland_buf(cpu, arg1, arg2);
1446     result_low = connect(arg0, (void *)charbuf, arg2);
1447     if ((int64_t)result_low < 0) {
1448     error_code = errno;
1449     error_flag = 1;
1450     }
1451     printf("connect!!!! res = %i error=%i\n",
1452     (int)result_low, (int)error_code);
1453     free(charbuf);
1454     break;
1455    
1456     case ULTRIX_SYS_fcntl:
1457     debug("[ fcntl(%i,%i,0x%x): TODO ]\n",
1458     (int)arg0, (int)arg1, (int)arg2);
1459     /* TODO: how about that third argument? */
1460     result_low = fcntl(arg0, arg1, arg2);
1461     if ((int64_t)result_low < 0) {
1462     error_code = errno;
1463     error_flag = 1;
1464     }
1465     printf("fcntl!!!! res = %i error=%i\n",
1466     (int)result_low, (int)error_code);
1467     break;
1468    
1469     case ULTRIX_SYS_stat43:
1470     charbuf = get_userland_string(cpu, arg0);
1471     debug("[ stat(\"%s\", 0x%llx): TODO ]\n",
1472     charbuf, (long long)arg1);
1473    
1474     if (arg1 != 0) {
1475     struct stat st;
1476     result_low = stat((char *)charbuf, &st);
1477     if ((int64_t)result_low < 0) {
1478     error_flag = 1;
1479     error_code = errno;
1480     } else {
1481     /* Fill in the Ultrix stat struct at arg1: */
1482    
1483     /* TODO */
1484     }
1485     } else {
1486     error_flag = 1;
1487     error_code = 1111; /* TODO: ultrix ENOMEM? */
1488     }
1489     free(charbuf);
1490     break;
1491    
1492     case ULTRIX_SYS_fstat:
1493 dpavlin 12 result_low = useremul_fstat(cpu, &error_code, arg0, arg1);
1494 dpavlin 2 break;
1495    
1496     case ULTRIX_SYS_getpagesize:
1497     debug("[ getpagesize() ]\n");
1498     result_low = 4096;
1499     break;
1500    
1501     case ULTRIX_SYS_getdtablesize:
1502     debug("[ getdtablesize() ]\n");
1503     result_low = getdtablesize();
1504     break;
1505    
1506     case ULTRIX_SYS_gethostname:
1507     debug("[ gethostname(0x%llx,%lli) ]\n",
1508     (long long)arg0, (long long)arg1);
1509     result_low = 0;
1510     if (arg1 != 0 && arg1 < 500000) {
1511     unsigned char *buf = malloc(arg1);
1512     unsigned int i;
1513    
1514     result_low = gethostname((char *)buf, arg1);
1515     for (i = 0; i<arg1 && i < arg1; i++)
1516     cpu->memory_rw(cpu, cpu->mem, arg0 + i,
1517     &buf[i], 1, MEM_WRITE, CACHE_NONE);
1518    
1519     free(buf);
1520     } else {
1521     error_flag = 1;
1522     error_code = 5555; /* TODO */ /* ENOMEM */
1523     }
1524     break;
1525    
1526     case ULTRIX_SYS_writev:
1527     descr = arg0;
1528     debug("[ writev(%lli,0x%llx,%lli) ]\n",
1529     (long long)arg0, (long long)arg1, (long long)arg2);
1530    
1531     if (arg1 != 0) {
1532     unsigned int i, total = 0;
1533    
1534     for (i=0; i<arg2; i++) {
1535     uint32_t iov_base, iov_len;
1536     iov_base = load_32bit_word(cpu,
1537     arg1 + 8*i + 0); /* char * */
1538     iov_len = load_32bit_word(cpu,
1539     arg1 + 8*i + 4); /* size_t */
1540    
1541     if (iov_len != 0) {
1542     unsigned char *charbuf =
1543     malloc(iov_len);
1544     if (charbuf == NULL) {
1545     fprintf(stderr, "out of memory"
1546     " in useremul__ultrix()\n");
1547     exit(1);
1548     }
1549    
1550     /* TODO: address validity check */
1551     cpu->memory_rw(cpu, cpu->mem, (uint64_t)
1552     iov_base, charbuf, iov_len,
1553     MEM_READ, CACHE_DATA);
1554     total += write(descr, charbuf, iov_len);
1555     free(charbuf);
1556     }
1557     }
1558    
1559     result_low = total;
1560     }
1561     break;
1562    
1563     case ULTRIX_SYS_gethostid:
1564     debug("[ gethostid() ]\n");
1565     /* This is supposed to return a unique 32-bit host id. */
1566     result_low = 0x12345678;
1567     break;
1568    
1569     case ULTRIX_SYS_gettimeofday:
1570     debug("[ gettimeofday(0x%llx,0x%llx) ]\n",
1571     (long long)arg0, (long long)arg1);
1572     result_low = gettimeofday(&tv, &tz);
1573     if (result_low) {
1574     error_flag = 1;
1575     error_code = errno;
1576     } else {
1577     if (arg0 != 0) {
1578     /* Store tv.tv_sec and tv.tv_usec
1579     as 'long' (32-bit) values: */
1580     store_32bit_word(cpu, arg0 + 0, tv.tv_sec);
1581     store_32bit_word(cpu, arg0 + 4, tv.tv_usec);
1582     }
1583     if (arg1 != 0) {
1584     /* Store tz.tz_minuteswest and
1585     tz.tz_dsttime as 'long' (32-bit) values: */
1586     store_32bit_word(cpu, arg1 + 0,
1587     tz.tz_minuteswest);
1588     store_32bit_word(cpu, arg1 + 4, tz.tz_dsttime);
1589     }
1590     }
1591     break;
1592    
1593     default:
1594     fatal("[ UNIMPLEMENTED ultrix syscall %i ]\n", sysnr);
1595     error_flag = 1;
1596     error_code = 78; /* ENOSYS */
1597     }
1598    
1599     /*
1600     * Ultrix/mips return values:
1601     *
1602     * TODO
1603     *
1604     * a3 is 0 if the syscall was ok, otherwise 1.
1605     * v0 (and sometimes v1) contain the result value.
1606     */
1607     cpu->cd.mips.gpr[MIPS_GPR_A3] = error_flag;
1608     if (error_flag)
1609     cpu->cd.mips.gpr[MIPS_GPR_V0] = error_code;
1610     else
1611     cpu->cd.mips.gpr[MIPS_GPR_V0] = result_low;
1612    
1613     if (result_high_set)
1614     cpu->cd.mips.gpr[MIPS_GPR_V1] = result_high;
1615    
1616     /* TODO */
1617     }
1618    
1619    
1620     /*
1621     * useremul_name_to_useremul():
1622     *
1623     * Example:
1624     * Input: name = "netbsd/pmax"
1625     * Output: sets *arch = ARCH_MIPS, *machine_name = "NetBSD/pmax",
1626     * and *cpu_name = "R3000".
1627     */
1628     void useremul_name_to_useremul(struct cpu *cpu, char *name, int *arch,
1629     char **machine_name, char **cpu_name)
1630     {
1631     struct syscall_emul *sep;
1632    
1633     sep = first_syscall_emul;
1634    
1635     while (sep != NULL) {
1636     if (strcasecmp(name, sep->name) == 0) {
1637     if (cpu_family_ptr_by_number(sep->arch) == NULL) {
1638     printf("\nSupport for the CPU family needed"
1639     " for '%s' userland emulation was not"
1640     " enabled at configuration time.\n",
1641     sep->name);
1642     exit(1);
1643     }
1644    
1645     if (cpu != NULL)
1646     cpu->useremul_syscall = sep->f;
1647    
1648     if (arch != NULL)
1649     *arch = sep->arch;
1650    
1651     if (machine_name != NULL) {
1652     *machine_name = strdup(sep->name);
1653     if (*machine_name == NULL) {
1654     printf("out of memory\n");
1655     exit(1);
1656     }
1657     }
1658    
1659     if (cpu_name != NULL) {
1660     *cpu_name = strdup(sep->cpu_name);
1661     if (*cpu_name == NULL) {
1662     printf("out of memory\n");
1663     exit(1);
1664     }
1665     }
1666     return;
1667     }
1668    
1669     sep = sep->next;
1670     }
1671    
1672     fatal("Unknown userland emulation '%s'\n", name);
1673     exit(1);
1674     }
1675    
1676    
1677     /*
1678     * add_useremul():
1679     *
1680     * For internal use, from useremul_init() only. Adds an emulation mode.
1681     */
1682     static void add_useremul(char *name, int arch, char *cpu_name,
1683     void (*f)(struct cpu *, uint32_t),
1684     void (*setup)(struct cpu *, int, char **))
1685     {
1686     struct syscall_emul *sep;
1687    
1688     sep = malloc(sizeof(struct syscall_emul));
1689     if (sep == NULL) {
1690     printf("add_useremul(): out of memory\n");
1691     exit(1);
1692     }
1693     memset(sep, 0, sizeof(sep));
1694    
1695     sep->name = name;
1696     sep->arch = arch;
1697     sep->cpu_name = cpu_name;
1698     sep->f = f;
1699     sep->setup = setup;
1700    
1701     sep->next = first_syscall_emul;
1702     first_syscall_emul = sep;
1703     }
1704    
1705    
1706     /*
1707     * useremul_list_emuls():
1708     *
1709     * List all available userland emulation modes. (Actually, only those which
1710     * have CPU support enabled.)
1711     */
1712     void useremul_list_emuls(void)
1713     {
1714     struct syscall_emul *sep;
1715     int iadd = 8;
1716    
1717     sep = first_syscall_emul;
1718    
1719     if (sep == NULL)
1720     return;
1721    
1722     debug("The following userland-only (syscall) emulation modes are"
1723     " available:\n\n");
1724     debug_indentation(iadd);
1725    
1726     while (sep != NULL) {
1727     if (cpu_family_ptr_by_number(sep->arch) != NULL) {
1728     debug("%s (default CPU \"%s\")\n",
1729     sep->name, sep->cpu_name);
1730     }
1731    
1732     sep = sep->next;
1733     }
1734    
1735     debug_indentation(-iadd);
1736     debug("\n(Most of these modes are bogus.)\n\n");
1737     }
1738    
1739    
1740     /*
1741     * useremul_init():
1742     *
1743     * This function should be called before any other useremul_*() function
1744     * is used.
1745     */
1746     void useremul_init(void)
1747     {
1748     /* Note: These are in reverse alphabetic order: */
1749    
1750     add_useremul("Ultrix", ARCH_MIPS, "R3000",
1751     useremul__ultrix, useremul__ultrix_setup);
1752    
1753     add_useremul("NetBSD/powerpc", ARCH_PPC, "PPC750",
1754     useremul__netbsd, useremul__netbsd_setup);
1755    
1756     add_useremul("NetBSD/pmax", ARCH_MIPS, "R3000",
1757     useremul__netbsd, useremul__netbsd_setup);
1758    
1759 dpavlin 14 add_useremul("NetBSD/arm", ARCH_ARM, "SA1110",
1760 dpavlin 12 useremul__netbsd, useremul__netbsd_setup);
1761    
1762 dpavlin 4 add_useremul("NetBSD/amd64", ARCH_X86, "AMD64",
1763     useremul__netbsd, useremul__netbsd_setup);
1764    
1765 dpavlin 14 add_useremul("NetBSD/alpha", ARCH_ALPHA, "Alpha",
1766     useremul__netbsd, useremul__netbsd_setup);
1767    
1768 dpavlin 2 add_useremul("Linux/PPC64", ARCH_PPC, "PPC970",
1769     useremul__linux, useremul__linux_setup);
1770    
1771 dpavlin 12 add_useremul("FreeBSD/Alpha", ARCH_ALPHA, "Alpha",
1772 dpavlin 2 useremul__freebsd, useremul__freebsd_setup);
1773     }
1774    

  ViewVC Help
Powered by ViewVC 1.1.26