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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 22 - (hide annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 43685 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


1 dpavlin 2 /*
2 dpavlin 22 * Copyright (C) 2004-2006 Anders Gavare. All rights reserved.
3 dpavlin 2 *
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 22 * $Id: useremul.c,v 1.70 2006/01/14 12:51:59 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 22 size_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 dpavlin 22 case 73:/* munmap. TODO */
703     res = 1;
704     break;
705    
706 dpavlin 12 case 117:res = useremul_getrusage(cpu, &err, arg0, arg1);
707     break;
708    
709     case 189:res = useremul_fstat(cpu, &err, arg0, arg1);
710     break;
711    
712     case 197:res = useremul_mmap(cpu, &err, arg0, arg1, arg2, arg3,
713     arg4, arg5);
714     break;
715    
716     default:fatal("useremul__freebsd(): syscall %i not yet "
717     "implemented\n", nr);
718 dpavlin 2 cpu->running = 0;
719     }
720 dpavlin 12
721     if (err) {
722     cpu->cd.alpha.r[ALPHA_A3] = 1;
723     cpu->cd.alpha.r[ALPHA_V0] = err;
724     } else {
725     cpu->cd.alpha.r[ALPHA_A3] = 0;
726     cpu->cd.alpha.r[ALPHA_V0] = res;
727     }
728 dpavlin 2 }
729    
730    
731     /*
732     * useremul__linux():
733     *
734     * Linux syscall emulation.
735     *
736     * TODO: How to make this work nicely with non-PPC archs.
737     */
738     static void useremul__linux(struct cpu *cpu, uint32_t code)
739     {
740     int nr;
741 dpavlin 12 int64_t res = 0, err = 0;
742 dpavlin 2 uint64_t arg0, arg1, arg2, arg3;
743    
744     if (code != 0) {
745     fatal("useremul__linux(): code %i: TODO\n", (int)code);
746     exit(1);
747     }
748    
749     nr = cpu->cd.ppc.gpr[0];
750     arg0 = cpu->cd.ppc.gpr[3];
751     arg1 = cpu->cd.ppc.gpr[4];
752     arg2 = cpu->cd.ppc.gpr[5];
753     arg3 = cpu->cd.ppc.gpr[6];
754    
755     switch (nr) {
756    
757     case LINUX_PPC_SYS_exit:
758 dpavlin 12 res = useremul_exit(cpu, arg0);
759 dpavlin 2 break;
760    
761     case LINUX_PPC_SYS_write:
762 dpavlin 12 res = useremul_write(cpu, &err, arg0, arg1, arg2);
763 dpavlin 2 break;
764    
765     default:
766     fatal("useremul__linux(): syscall %i not yet implemented\n",
767     nr);
768     cpu->running = 0;
769     }
770 dpavlin 12
771     /* return res: TODO */
772 dpavlin 2 }
773    
774    
775     /*
776     * useremul__netbsd():
777     *
778     * NetBSD syscall emulation.
779     */
780     static void useremul__netbsd(struct cpu *cpu, uint32_t code)
781     {
782     int error_flag = 0, result_high_set = 0;
783     uint64_t arg0=0,arg1=0,arg2=0,arg3=0,stack0=0,stack1=0,stack2=0;
784     int sysnr = 0;
785 dpavlin 12 int64_t error_code = 0;
786 dpavlin 2 uint64_t result_low = 0;
787     uint64_t result_high = 0;
788     struct timeval tv;
789     struct timezone tz;
790     int descr;
791     uint64_t length, mipsbuf, flags;
792     unsigned char *charbuf;
793     uint32_t sysctl_name, sysctl_namelen, sysctl_oldp,
794     sysctl_oldlenp, sysctl_newp, sysctl_newlen;
795     uint32_t name0, name1, name2, name3;
796    
797     switch (cpu->machine->arch) {
798     case ARCH_MIPS:
799     sysnr = cpu->cd.mips.gpr[MIPS_GPR_V0];
800     if (sysnr == NETBSD_SYS___syscall) {
801     sysnr = cpu->cd.mips.gpr[MIPS_GPR_A0] +
802     (cpu->cd.mips.gpr[MIPS_GPR_A1] << 32);
803     arg0 = cpu->cd.mips.gpr[MIPS_GPR_A2];
804     arg1 = cpu->cd.mips.gpr[MIPS_GPR_A3];
805     /* TODO: stack arguments? Are these correct? */
806     arg2 = load_32bit_word(cpu,
807     cpu->cd.mips.gpr[MIPS_GPR_SP] + 8);
808     arg3 = load_32bit_word(cpu,
809     cpu->cd.mips.gpr[MIPS_GPR_SP] + 16);
810     stack0 = load_32bit_word(cpu,
811     cpu->cd.mips.gpr[MIPS_GPR_SP] + 24);
812     stack1 = load_32bit_word(cpu,
813     cpu->cd.mips.gpr[MIPS_GPR_SP] + 32);
814     stack2 = load_32bit_word(cpu,
815     cpu->cd.mips.gpr[MIPS_GPR_SP] + 40);
816     } else {
817     arg0 = cpu->cd.mips.gpr[MIPS_GPR_A0];
818     arg1 = cpu->cd.mips.gpr[MIPS_GPR_A1];
819     arg2 = cpu->cd.mips.gpr[MIPS_GPR_A2];
820     arg3 = cpu->cd.mips.gpr[MIPS_GPR_A3];
821     /* TODO: stack arguments? Are these correct? */
822     stack0 = load_32bit_word(cpu,
823     cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
824     stack1 = load_32bit_word(cpu,
825     cpu->cd.mips.gpr[MIPS_GPR_SP] + 8);
826     stack2 = load_32bit_word(cpu,
827     cpu->cd.mips.gpr[MIPS_GPR_SP] + 12);
828     }
829     break;
830    
831     case ARCH_PPC:
832     sysnr = cpu->cd.ppc.gpr[0];
833     arg0 = cpu->cd.ppc.gpr[3];
834     arg1 = cpu->cd.ppc.gpr[4];
835     arg2 = cpu->cd.ppc.gpr[5];
836     arg3 = cpu->cd.ppc.gpr[6];
837     /* TODO: More arguments? Stack arguments? */
838     break;
839 dpavlin 14
840     case ARCH_ARM:
841     sysnr = code & 0xfffff;
842     arg0 = cpu->cd.arm.r[0];
843     arg1 = cpu->cd.arm.r[1];
844     arg2 = cpu->cd.arm.r[2];
845     arg3 = cpu->cd.arm.r[3];
846     /* TODO: More arguments? Stack arguments? */
847     break;
848    
849     default:fatal("netbsd syscall for this arch: TODO\n");
850     exit(1);
851 dpavlin 2 }
852    
853     /*
854 dpavlin 18 * NOTE/TODO: The following code should not be CPU arch dependent!
855 dpavlin 2 */
856    
857     switch (sysnr) {
858    
859     case NETBSD_SYS_exit:
860     debug("[ exit(%i) ]\n", (int)arg0);
861     cpu->running = 0;
862     cpu->machine->exit_without_entering_debugger = 1;
863     break;
864    
865     case NETBSD_SYS_read:
866     debug("[ read(%i,0x%llx,%lli) ]\n",
867     (int)arg0, (long long)arg1, (long long)arg2);
868    
869     if (arg2 != 0) {
870     charbuf = malloc(arg2);
871     if (charbuf == NULL) {
872     fprintf(stderr, "out of memory in "
873     "useremul__netbsd()\n");
874     exit(1);
875     }
876     result_low = read(arg0, charbuf, arg2);
877     if ((int64_t)result_low < 0) {
878     error_code = errno;
879     error_flag = 1;
880     }
881    
882     /* TODO: address validity check */
883     cpu->memory_rw(cpu, cpu->mem, arg1, charbuf,
884     arg2, MEM_WRITE, CACHE_DATA);
885     free(charbuf);
886     }
887     break;
888    
889     case NETBSD_SYS_write:
890     descr = arg0;
891     mipsbuf = arg1;
892     length = arg2;
893     debug("[ write(%i,0x%llx,%lli) ]\n",
894     (int)descr, (long long)mipsbuf, (long long)length);
895     if (length != 0) {
896     charbuf = malloc(length);
897     if (charbuf == NULL) {
898     fprintf(stderr, "out of memory in "
899     "useremul__netbsd()\n");
900     exit(1);
901     }
902     /* TODO: address validity check */
903     cpu->memory_rw(cpu, cpu->mem, mipsbuf, charbuf,
904     length, MEM_READ, CACHE_DATA);
905     result_low = write(descr, charbuf, length);
906     if ((int64_t)result_low < 0) {
907     error_code = errno;
908     error_flag = 1;
909     }
910     free(charbuf);
911     }
912     break;
913    
914     case NETBSD_SYS_open:
915     charbuf = get_userland_string(cpu, arg0);
916     debug("[ open(\"%s\", 0x%llx, 0x%llx) ]\n",
917     charbuf, (long long)arg1, (long long)arg2);
918     result_low = open((char *)charbuf, arg1, arg2);
919     if ((int64_t)result_low < 0) {
920     error_flag = 1;
921     error_code = errno;
922     }
923     free(charbuf);
924     break;
925    
926     case NETBSD_SYS_close:
927     descr = arg0;
928     debug("[ close(%i) ]\n", (int)descr);
929     error_code = close(descr);
930     if (error_code != 0)
931     error_flag = 1;
932     break;
933    
934     case NETBSD_SYS_access:
935     charbuf = get_userland_string(cpu, arg0);
936     debug("[ access(\"%s\", 0x%llx) ]\n",
937     charbuf, (long long) arg1);
938     result_low = access((char *)charbuf, arg1);
939     if (result_low != 0) {
940     error_flag = 1;
941     error_code = errno;
942     }
943     free(charbuf);
944     break;
945    
946     case NETBSD_SYS_getuid:
947 dpavlin 12 result_low = useremul_getuid(cpu);
948 dpavlin 2 break;
949    
950     case NETBSD_SYS_geteuid:
951     debug("[ geteuid() ]\n");
952     result_low = geteuid();
953     break;
954    
955     case NETBSD_SYS_getgid:
956     debug("[ getgid() ]\n");
957     result_low = getgid();
958     break;
959    
960     case NETBSD_SYS_getegid:
961     debug("[ getegid() ]\n");
962     result_low = getegid();
963     break;
964    
965     case NETBSD_SYS_getfsstat:
966     mipsbuf = arg0;
967     length = arg1;
968     flags = arg2;
969     debug("[ getfsstat(0x%llx,%lli,0x%llx) ]\n",
970     (long long)mipsbuf, (long long)length,
971     (long long)flags);
972    
973     result_low = 0; /* nr of mounted filesystems,
974     for now (TODO) */
975    
976     /* Fill in the struct statfs buffer at arg0...
977     copy data from the host's getfsstat(). TODO */
978     #if 1
979     result_low = 1;
980     store_32bit_word(cpu, mipsbuf + 0, 0); /* f_spare2 */
981     store_32bit_word(cpu, mipsbuf + 4, 1024); /* f_bsize */
982     store_32bit_word(cpu, mipsbuf + 8, 65536); /* f_iosize */
983     store_32bit_word(cpu, mipsbuf + 12, 100); /* f_blocks */
984     store_32bit_word(cpu, mipsbuf + 16, 50); /* f_bfree */
985     store_32bit_word(cpu, mipsbuf + 20, 10); /* f_bavail */
986     store_32bit_word(cpu, mipsbuf + 24, 50); /* f_files */
987     store_32bit_word(cpu, mipsbuf + 28, 25); /* f_ffree */
988     store_32bit_word(cpu, mipsbuf + 28, 0x1234); /* f_fsid */
989     store_32bit_word(cpu, mipsbuf + 32, 0); /* f_owner */
990     store_32bit_word(cpu, mipsbuf + 36, 0); /* f_type */
991     store_32bit_word(cpu, mipsbuf + 40, 0); /* f_flags */
992     store_32bit_word(cpu, mipsbuf + 44, 0); /* f_fspare[0] */
993     store_32bit_word(cpu, mipsbuf + 48, 0); /* f_fspare[1] */
994     store_string(cpu, mipsbuf + 52, "ffs"); /* f_typename */
995     #define MFSNAMELEN 16
996     #define MNAMELEN 90
997     store_string(cpu, mipsbuf + 52 + MFSNAMELEN, "/");
998     /* f_mntonname */
999     store_string(cpu, mipsbuf + 52 + MFSNAMELEN + MNAMELEN, "ffs");
1000     /* f_mntfromname */
1001     #endif
1002     break;
1003    
1004     case NETBSD_SYS_break:
1005 dpavlin 12 useremul_break(cpu, arg0);
1006 dpavlin 2 break;
1007    
1008     case NETBSD_SYS_readlink:
1009 dpavlin 12 result_low = useremul_readlink(cpu, &error_code,
1010     arg0, arg1, arg2);
1011 dpavlin 2 break;
1012    
1013     case NETBSD_SYS_sync:
1014 dpavlin 12 useremul_sync(cpu);
1015 dpavlin 2 break;
1016    
1017     case NETBSD_SYS_gettimeofday:
1018     debug("[ gettimeofday(0x%llx,0x%llx) ]\n",
1019     (long long)arg0, (long long)arg1);
1020     result_low = gettimeofday(&tv, &tz);
1021     if (result_low) {
1022     error_flag = 1;
1023     error_code = errno;
1024     } else {
1025     if (arg0 != 0) {
1026     /* Store tv.tv_sec and tv.tv_usec as
1027     'long' (32-bit) values: */
1028     store_32bit_word(cpu, arg0 + 0,
1029     tv.tv_sec);
1030     store_32bit_word(cpu, arg0 + 4,
1031     tv.tv_usec);
1032     }
1033     if (arg1 != 0) {
1034     /* Store tz.tz_minuteswest and
1035     tz.tz_dsttime as 'long'
1036     (32-bit) values: */
1037     store_32bit_word(cpu, arg1 + 0,
1038     tz.tz_minuteswest);
1039     store_32bit_word(cpu, arg1 + 4,
1040     tz.tz_dsttime);
1041     }
1042     }
1043     break;
1044    
1045     case NETBSD_SYS_mmap:
1046     debug("[ mmap(0x%x,%i,%i,%i,%i,0x%llx): TODO ]\n",
1047     arg0, arg1, arg2, arg3, stack0, (long long)stack1);
1048    
1049     if ((int32_t)stack0 == -1) {
1050     /*
1051     * Anonymous allocation:
1052     *
1053     * TODO: Fix this!!!
1054     *
1055     * This quick hack simply allocates anonymous
1056     * mmap memory approximately below the stack.
1057     * This will probably not work with dynamically
1058     * loaded libraries and such.
1059     */
1060     static uint32_t mmap_anon_ptr = 0x70000000;
1061     mmap_anon_ptr -= arg1;
1062     /* round down to page boundary: */
1063     mmap_anon_ptr &= ~4095;
1064     debug("ANON: %i bytes at 0x%08x (TODO: not "
1065     "working yet?)\n", (int)arg1,
1066     mmap_anon_ptr);
1067     result_low = mmap_anon_ptr;
1068     } else {
1069     /* Return NULL for now */
1070     }
1071     break;
1072    
1073     case NETBSD_SYS_dup:
1074     debug("[ dup(%i) ]\n", (int)arg0);
1075     result_low = dup(arg0);
1076     if ((int64_t)result_low < 0) {
1077     error_code = errno;
1078     error_flag = 1;
1079     }
1080     break;
1081    
1082     case NETBSD_SYS_socket:
1083     debug("[ socket(%i,%i,%i) ]\n",
1084     (int)arg0, (int)arg1, (int)arg2);
1085     result_low = socket(arg0,arg1,arg2);
1086     if ((int64_t)result_low < 0) {
1087     error_code = errno;
1088     error_flag = 1;
1089     }
1090     break;
1091    
1092     case NETBSD_SYS_issetugid:
1093     debug("[ issetugid() ]\n");
1094     /* TODO: actually call the real issetugid? */
1095     break;
1096    
1097     case NETBSD_SYS_nanosleep:
1098     debug("[ nanosleep(0x%llx,0x%llx) ]\n",
1099     (long long)arg0, (long long)arg1);
1100    
1101     if (arg0 != 0) {
1102     uint32_t sec = load_32bit_word(cpu, arg0 + 0);
1103     uint32_t nsec = load_32bit_word(cpu, arg0 + 4);
1104     struct timespec ts;
1105     ts.tv_sec = sec;
1106     ts.tv_nsec = nsec;
1107     result_low = nanosleep(&ts, NULL);
1108     if (result_low)
1109     fprintf(stderr, "netbsd emulation "
1110     "nanosleep() failed\n");
1111     /* TODO: arg1 */
1112     } else {
1113     error_flag = 1;
1114     error_code = 14; /* EFAULT */
1115     }
1116     break;
1117    
1118     case NETBSD_SYS___fstat13:
1119     debug("[ __fstat13(%lli,0x%llx): TODO ]\n",
1120     (long long)arg0, (long long)arg1);
1121     error_flag = 1;
1122     error_code = 9; /* EBADF */
1123     break;
1124    
1125     case NETBSD_SYS___getcwd:
1126     debug("[ __getcwd(0x%llx,%lli): TODO ]\n",
1127     (long long)arg0, (long long)arg1);
1128     if (arg1 != 0 && arg1 < 500000) {
1129     char *buf = malloc(arg1);
1130     unsigned int i;
1131    
1132     getcwd(buf, arg1);
1133    
1134     /* zero-terminate in host's space: */
1135     buf[arg1 - 1] = 0;
1136    
1137     for (i = 0; i<arg1 && i < arg1; i++)
1138     cpu->memory_rw(cpu, cpu->mem, arg0 + i,
1139     (unsigned char *)&buf[i], 1,
1140     MEM_WRITE, CACHE_NONE);
1141    
1142     /* zero-terminate in emulated space: */
1143     cpu->memory_rw(cpu, cpu->mem, arg0 + arg1-1,
1144     (unsigned char *)&buf[arg1 - 1],
1145     1, MEM_WRITE, CACHE_NONE);
1146    
1147     free(buf);
1148     }
1149     result_low = arg0;
1150     break;
1151    
1152     case NETBSD_SYS___sigaction14:
1153     debug("[ __sigaction14(%lli,0x%llx,0x%llx): TODO ]\n",
1154     (long long)arg0, (long long)arg1, (long long)arg2);
1155     error_flag = 1;
1156     error_code = 9; /* EBADF */
1157     break;
1158    
1159     case NETBSD_SYS___sysctl:
1160     sysctl_name = arg0;
1161     sysctl_namelen = arg1;
1162     sysctl_oldp = arg2;
1163     sysctl_oldlenp = arg3;
1164     sysctl_newp = load_32bit_word(cpu,
1165     cpu->cd.mips.gpr[MIPS_GPR_SP]);
1166     /* TODO: +4 and +8 ?? */
1167     sysctl_newlen = load_32bit_word(cpu,
1168     cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
1169     debug("[ __sysctl(");
1170    
1171     name0 = load_32bit_word(cpu, sysctl_name + 0);
1172     name1 = load_32bit_word(cpu, sysctl_name + 4);
1173     name2 = load_32bit_word(cpu, sysctl_name + 8);
1174     name3 = load_32bit_word(cpu, sysctl_name + 12);
1175     debug("name (@ 0x%08x) = %i, %i, %i, %i) ]\n",
1176     sysctl_name, name0, name1, name2, name3);
1177    
1178     if (name0 == CTL_KERN && name1 == KERN_HOSTNAME) {
1179     char hname[256];
1180     hname[0] = '\0';
1181     gethostname(hname, sizeof(hname));
1182     hname[sizeof(hname)-1] = '\0';
1183     if (sysctl_oldp != 0)
1184     store_string(cpu, sysctl_oldp, hname);
1185     if (sysctl_oldlenp != 0)
1186     store_32bit_word(cpu, sysctl_oldlenp,
1187     strlen(hname));
1188     } else if (name0 == CTL_HW && name1 == HW_PAGESIZE) {
1189     if (sysctl_oldp != 0)
1190     store_32bit_word(cpu,
1191     sysctl_oldp, 4096);
1192     if (sysctl_oldlenp != 0)
1193     store_32bit_word(cpu,
1194     sysctl_oldlenp, sizeof(uint32_t));
1195     } else {
1196     error_flag = 1;
1197     error_code = 2; /* ENOENT */
1198     }
1199     break;
1200    
1201     default:
1202     fatal("[ UNIMPLEMENTED netbsd syscall %i ]\n", sysnr);
1203     error_flag = 1;
1204     error_code = 78; /* ENOSYS */
1205     }
1206    
1207    
1208     switch (cpu->machine->arch) {
1209 dpavlin 14 case ARCH_ARM:
1210     /* NetBSD/arm return values: */
1211     cpu->cd.arm.r[0] = result_low;
1212     cpu->cd.arm.cpsr &= ~ARM_FLAG_C;
1213     if (error_flag) {
1214     cpu->cd.arm.cpsr |= ARM_FLAG_C;
1215     cpu->cd.arm.r[0] = error_code;
1216     }
1217     if (result_high_set)
1218     cpu->cd.arm.r[1] = result_high;
1219 dpavlin 20 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1220 dpavlin 14 break;
1221 dpavlin 2 case ARCH_MIPS:
1222     /*
1223     * NetBSD/mips return values:
1224     *
1225     * a3 is 0 if the syscall was ok, otherwise 1.
1226     * v0 (and sometimes v1) contain the result value.
1227     */
1228     cpu->cd.mips.gpr[MIPS_GPR_A3] = error_flag;
1229     if (error_flag)
1230     cpu->cd.mips.gpr[MIPS_GPR_V0] = error_code;
1231     else
1232     cpu->cd.mips.gpr[MIPS_GPR_V0] = result_low;
1233    
1234     if (result_high_set)
1235     cpu->cd.mips.gpr[MIPS_GPR_V1] = result_high;
1236     break;
1237     case ARCH_PPC:
1238     /*
1239     * NetBSD/powerpc return values:
1240     *
1241     * TODO
1242     */
1243     cpu->cd.ppc.gpr[3] = result_low;
1244    
1245     if (result_high_set)
1246     cpu->cd.ppc.gpr[4] = result_high;
1247     break;
1248     }
1249     }
1250    
1251    
1252     /*
1253     * useremul__ultrix():
1254     *
1255     * Ultrix syscall emulation.
1256     */
1257     static void useremul__ultrix(struct cpu *cpu, uint32_t code)
1258     {
1259     int error_flag = 0, result_high_set = 0;
1260     uint64_t arg0,arg1,arg2,arg3,stack0=0,stack1=0,stack2;
1261     int sysnr = 0;
1262 dpavlin 12 int64_t error_code = 0;
1263 dpavlin 2 uint64_t result_low = 0;
1264     uint64_t result_high = 0;
1265     struct timeval tv;
1266     struct timezone tz;
1267     int descr;
1268     uint64_t length, mipsbuf;
1269     unsigned char *charbuf;
1270    
1271     /*
1272     * Ultrix/pmax gets the syscall number in register v0,
1273     * and syscall arguments in registers a0, a1, ...
1274     *
1275     * TODO: If there is a __syscall-like syscall (as in NetBSD)
1276     * then 64-bit args may be passed in two registers or something...
1277     * If so, then copy from the section above (NetBSD).
1278     */
1279     sysnr = cpu->cd.mips.gpr[MIPS_GPR_V0];
1280    
1281     arg0 = cpu->cd.mips.gpr[MIPS_GPR_A0];
1282     arg1 = cpu->cd.mips.gpr[MIPS_GPR_A1];
1283     arg2 = cpu->cd.mips.gpr[MIPS_GPR_A2];
1284     arg3 = cpu->cd.mips.gpr[MIPS_GPR_A3];
1285     /* TODO: stack arguments? Are these correct? */
1286     stack0 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 0);
1287     stack1 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
1288     stack2 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 8);
1289    
1290     switch (sysnr) {
1291    
1292     case ULTRIX_SYS_exit:
1293     debug("[ exit(%i) ]\n", (int)arg0);
1294     cpu->running = 0;
1295     cpu->machine->exit_without_entering_debugger = 1;
1296     break;
1297    
1298     case ULTRIX_SYS_read:
1299     debug("[ read(%i,0x%llx,%lli) ]\n",
1300     (int)arg0, (long long)arg1, (long long)arg2);
1301    
1302     if (arg2 != 0) {
1303     charbuf = malloc(arg2);
1304     if (charbuf == NULL) {
1305     fprintf(stderr, "out of memory in "
1306     "useremul__ultrix()\n");
1307     exit(1);
1308     }
1309    
1310     result_low = read(arg0, charbuf, arg2);
1311     if ((int64_t)result_low < 0) {
1312     error_code = errno;
1313     error_flag = 1;
1314     }
1315    
1316     /* TODO: address validity check */
1317     cpu->memory_rw(cpu, cpu->mem, arg1, charbuf,
1318     arg2, MEM_WRITE, CACHE_DATA);
1319    
1320     free(charbuf);
1321     }
1322     break;
1323    
1324     case ULTRIX_SYS_write:
1325     descr = arg0;
1326     mipsbuf = arg1;
1327     length = arg2;
1328     debug("[ write(%i,0x%llx,%lli) ]\n",
1329     (int)descr, (long long)mipsbuf, (long long)length);
1330    
1331     if (length != 0) {
1332     charbuf = malloc(length);
1333     if (charbuf == NULL) {
1334     fprintf(stderr, "out of memory in "
1335     "useremul__ultrix()\n");
1336     exit(1);
1337     }
1338    
1339     /* TODO: address validity check */
1340     cpu->memory_rw(cpu, cpu->mem, mipsbuf, charbuf,
1341     length, MEM_READ, CACHE_DATA);
1342    
1343     result_low = write(descr, charbuf, length);
1344     if ((int64_t)result_low < 0) {
1345     error_code = errno;
1346     error_flag = 1;
1347     }
1348     free(charbuf);
1349     }
1350     break;
1351    
1352     case ULTRIX_SYS_open:
1353     charbuf = get_userland_string(cpu, arg0);
1354     debug("[ open(\"%s\", 0x%llx, 0x%llx) ]\n",
1355     charbuf, (long long)arg1, (long long)arg2);
1356    
1357     result_low = open((char *)charbuf, arg1, arg2);
1358     if ((int64_t)result_low < 0) {
1359     error_flag = 1;
1360     error_code = errno;
1361     }
1362     free(charbuf);
1363     break;
1364    
1365     case ULTRIX_SYS_close:
1366     descr = arg0;
1367     debug("[ close(%i) ]\n", (int)descr);
1368    
1369     /* Special case because some Ultrix programs tend
1370     to close low descriptors: */
1371     if (descr <= 2) {
1372     error_flag = 1;
1373     error_code = 2; /* TODO: Ultrix ENOENT error code */
1374     break;
1375     }
1376    
1377     error_code = close(descr);
1378     if (error_code != 0)
1379     error_flag = 1;
1380     break;
1381    
1382     case ULTRIX_SYS_break:
1383 dpavlin 12 useremul_break(cpu, arg0);
1384 dpavlin 2 break;
1385    
1386     case ULTRIX_SYS_sync:
1387 dpavlin 12 useremul_sync(cpu);
1388 dpavlin 2 break;
1389    
1390     case ULTRIX_SYS_getuid:
1391 dpavlin 12 result_low = useremul_getuid(cpu);
1392 dpavlin 2 break;
1393    
1394     case ULTRIX_SYS_getgid:
1395     debug("[ getgid() ]\n");
1396     result_low = getgid();
1397     break;
1398    
1399     case ULTRIX_SYS_dup:
1400     debug("[ dup(%i) ]\n", (int)arg0);
1401     result_low = dup(arg0);
1402     if ((int64_t)result_low < 0) {
1403     error_code = errno;
1404     error_flag = 1;
1405     }
1406     break;
1407    
1408     case ULTRIX_SYS_socket:
1409     debug("[ socket(%i,%i,%i) ]\n",
1410     (int)arg0, (int)arg1, (int)arg2);
1411     result_low = socket(arg0,arg1,arg2);
1412     if ((int64_t)result_low < 0) {
1413     error_code = errno;
1414     error_flag = 1;
1415     }
1416     break;
1417    
1418     case ULTRIX_SYS_select:
1419     debug("[ select(%i,0x%x,0x%x,0x%x,0x%x): TODO ]\n",
1420     (int)arg0, (int)arg1, (int)arg2, (int)arg3, (int)stack0);
1421    
1422     /* TODO */
1423     {
1424     fd_set fdset;
1425     FD_SET(3, &fdset);
1426     result_low = select(4, &fdset, NULL, NULL, NULL);
1427     }
1428     break;
1429    
1430     case ULTRIX_SYS_setsockopt:
1431     debug("[ setsockopt(%i,%i,%i,0x%x,%i): TODO ]\n",
1432     (int)arg0, (int)arg1, (int)arg2, (int)arg3, (int)stack0);
1433     /* TODO: len is not 4, len is stack0? */
1434     charbuf = get_userland_buf(cpu, arg3, 4);
1435     /* TODO: endianness of charbuf, etc */
1436     result_low = setsockopt(arg0, arg1, arg2, (void *)charbuf, 4);
1437     if ((int64_t)result_low < 0) {
1438     error_code = errno;
1439     error_flag = 1;
1440     }
1441     free(charbuf);
1442     printf("setsockopt!!!! res = %i error=%i\n",
1443     (int)result_low, (int)error_code);
1444     break;
1445    
1446     case ULTRIX_SYS_connect:
1447     debug("[ connect(%i,0x%x,%i) ]\n",
1448     (int)arg0, (int)arg1, (int)arg2);
1449     charbuf = get_userland_buf(cpu, arg1, arg2);
1450     result_low = connect(arg0, (void *)charbuf, arg2);
1451     if ((int64_t)result_low < 0) {
1452     error_code = errno;
1453     error_flag = 1;
1454     }
1455     printf("connect!!!! res = %i error=%i\n",
1456     (int)result_low, (int)error_code);
1457     free(charbuf);
1458     break;
1459    
1460     case ULTRIX_SYS_fcntl:
1461     debug("[ fcntl(%i,%i,0x%x): TODO ]\n",
1462     (int)arg0, (int)arg1, (int)arg2);
1463     /* TODO: how about that third argument? */
1464     result_low = fcntl(arg0, arg1, arg2);
1465     if ((int64_t)result_low < 0) {
1466     error_code = errno;
1467     error_flag = 1;
1468     }
1469     printf("fcntl!!!! res = %i error=%i\n",
1470     (int)result_low, (int)error_code);
1471     break;
1472    
1473     case ULTRIX_SYS_stat43:
1474     charbuf = get_userland_string(cpu, arg0);
1475     debug("[ stat(\"%s\", 0x%llx): TODO ]\n",
1476     charbuf, (long long)arg1);
1477    
1478     if (arg1 != 0) {
1479     struct stat st;
1480     result_low = stat((char *)charbuf, &st);
1481     if ((int64_t)result_low < 0) {
1482     error_flag = 1;
1483     error_code = errno;
1484     } else {
1485     /* Fill in the Ultrix stat struct at arg1: */
1486    
1487     /* TODO */
1488     }
1489     } else {
1490     error_flag = 1;
1491     error_code = 1111; /* TODO: ultrix ENOMEM? */
1492     }
1493     free(charbuf);
1494     break;
1495    
1496     case ULTRIX_SYS_fstat:
1497 dpavlin 12 result_low = useremul_fstat(cpu, &error_code, arg0, arg1);
1498 dpavlin 2 break;
1499    
1500     case ULTRIX_SYS_getpagesize:
1501     debug("[ getpagesize() ]\n");
1502     result_low = 4096;
1503     break;
1504    
1505     case ULTRIX_SYS_getdtablesize:
1506     debug("[ getdtablesize() ]\n");
1507     result_low = getdtablesize();
1508     break;
1509    
1510     case ULTRIX_SYS_gethostname:
1511     debug("[ gethostname(0x%llx,%lli) ]\n",
1512     (long long)arg0, (long long)arg1);
1513     result_low = 0;
1514     if (arg1 != 0 && arg1 < 500000) {
1515     unsigned char *buf = malloc(arg1);
1516     unsigned int i;
1517    
1518     result_low = gethostname((char *)buf, arg1);
1519     for (i = 0; i<arg1 && i < arg1; i++)
1520     cpu->memory_rw(cpu, cpu->mem, arg0 + i,
1521     &buf[i], 1, MEM_WRITE, CACHE_NONE);
1522    
1523     free(buf);
1524     } else {
1525     error_flag = 1;
1526     error_code = 5555; /* TODO */ /* ENOMEM */
1527     }
1528     break;
1529    
1530     case ULTRIX_SYS_writev:
1531     descr = arg0;
1532     debug("[ writev(%lli,0x%llx,%lli) ]\n",
1533     (long long)arg0, (long long)arg1, (long long)arg2);
1534    
1535     if (arg1 != 0) {
1536     unsigned int i, total = 0;
1537    
1538     for (i=0; i<arg2; i++) {
1539     uint32_t iov_base, iov_len;
1540     iov_base = load_32bit_word(cpu,
1541     arg1 + 8*i + 0); /* char * */
1542     iov_len = load_32bit_word(cpu,
1543     arg1 + 8*i + 4); /* size_t */
1544    
1545     if (iov_len != 0) {
1546     unsigned char *charbuf =
1547     malloc(iov_len);
1548     if (charbuf == NULL) {
1549     fprintf(stderr, "out of memory"
1550     " in useremul__ultrix()\n");
1551     exit(1);
1552     }
1553    
1554     /* TODO: address validity check */
1555     cpu->memory_rw(cpu, cpu->mem, (uint64_t)
1556     iov_base, charbuf, iov_len,
1557     MEM_READ, CACHE_DATA);
1558     total += write(descr, charbuf, iov_len);
1559     free(charbuf);
1560     }
1561     }
1562    
1563     result_low = total;
1564     }
1565     break;
1566    
1567     case ULTRIX_SYS_gethostid:
1568     debug("[ gethostid() ]\n");
1569     /* This is supposed to return a unique 32-bit host id. */
1570     result_low = 0x12345678;
1571     break;
1572    
1573     case ULTRIX_SYS_gettimeofday:
1574     debug("[ gettimeofday(0x%llx,0x%llx) ]\n",
1575     (long long)arg0, (long long)arg1);
1576     result_low = gettimeofday(&tv, &tz);
1577     if (result_low) {
1578     error_flag = 1;
1579     error_code = errno;
1580     } else {
1581     if (arg0 != 0) {
1582     /* Store tv.tv_sec and tv.tv_usec
1583     as 'long' (32-bit) values: */
1584     store_32bit_word(cpu, arg0 + 0, tv.tv_sec);
1585     store_32bit_word(cpu, arg0 + 4, tv.tv_usec);
1586     }
1587     if (arg1 != 0) {
1588     /* Store tz.tz_minuteswest and
1589     tz.tz_dsttime as 'long' (32-bit) values: */
1590     store_32bit_word(cpu, arg1 + 0,
1591     tz.tz_minuteswest);
1592     store_32bit_word(cpu, arg1 + 4, tz.tz_dsttime);
1593     }
1594     }
1595     break;
1596    
1597     default:
1598     fatal("[ UNIMPLEMENTED ultrix syscall %i ]\n", sysnr);
1599     error_flag = 1;
1600     error_code = 78; /* ENOSYS */
1601     }
1602    
1603     /*
1604     * Ultrix/mips return values:
1605     *
1606     * TODO
1607     *
1608     * a3 is 0 if the syscall was ok, otherwise 1.
1609     * v0 (and sometimes v1) contain the result value.
1610     */
1611     cpu->cd.mips.gpr[MIPS_GPR_A3] = error_flag;
1612     if (error_flag)
1613     cpu->cd.mips.gpr[MIPS_GPR_V0] = error_code;
1614     else
1615     cpu->cd.mips.gpr[MIPS_GPR_V0] = result_low;
1616    
1617     if (result_high_set)
1618     cpu->cd.mips.gpr[MIPS_GPR_V1] = result_high;
1619    
1620     /* TODO */
1621     }
1622    
1623    
1624     /*
1625     * useremul_name_to_useremul():
1626     *
1627     * Example:
1628     * Input: name = "netbsd/pmax"
1629     * Output: sets *arch = ARCH_MIPS, *machine_name = "NetBSD/pmax",
1630     * and *cpu_name = "R3000".
1631     */
1632     void useremul_name_to_useremul(struct cpu *cpu, char *name, int *arch,
1633     char **machine_name, char **cpu_name)
1634     {
1635     struct syscall_emul *sep;
1636    
1637     sep = first_syscall_emul;
1638    
1639     while (sep != NULL) {
1640     if (strcasecmp(name, sep->name) == 0) {
1641     if (cpu_family_ptr_by_number(sep->arch) == NULL) {
1642     printf("\nSupport for the CPU family needed"
1643     " for '%s' userland emulation was not"
1644     " enabled at configuration time.\n",
1645     sep->name);
1646     exit(1);
1647     }
1648    
1649     if (cpu != NULL)
1650     cpu->useremul_syscall = sep->f;
1651    
1652     if (arch != NULL)
1653     *arch = sep->arch;
1654    
1655     if (machine_name != NULL) {
1656     *machine_name = strdup(sep->name);
1657     if (*machine_name == NULL) {
1658     printf("out of memory\n");
1659     exit(1);
1660     }
1661     }
1662    
1663     if (cpu_name != NULL) {
1664     *cpu_name = strdup(sep->cpu_name);
1665     if (*cpu_name == NULL) {
1666     printf("out of memory\n");
1667     exit(1);
1668     }
1669     }
1670     return;
1671     }
1672    
1673     sep = sep->next;
1674     }
1675    
1676     fatal("Unknown userland emulation '%s'\n", name);
1677     exit(1);
1678     }
1679    
1680    
1681     /*
1682     * add_useremul():
1683     *
1684     * For internal use, from useremul_init() only. Adds an emulation mode.
1685     */
1686     static void add_useremul(char *name, int arch, char *cpu_name,
1687     void (*f)(struct cpu *, uint32_t),
1688     void (*setup)(struct cpu *, int, char **))
1689     {
1690     struct syscall_emul *sep;
1691    
1692     sep = malloc(sizeof(struct syscall_emul));
1693     if (sep == NULL) {
1694     printf("add_useremul(): out of memory\n");
1695     exit(1);
1696     }
1697     memset(sep, 0, sizeof(sep));
1698    
1699     sep->name = name;
1700     sep->arch = arch;
1701     sep->cpu_name = cpu_name;
1702     sep->f = f;
1703     sep->setup = setup;
1704    
1705     sep->next = first_syscall_emul;
1706     first_syscall_emul = sep;
1707     }
1708    
1709    
1710     /*
1711     * useremul_list_emuls():
1712     *
1713     * List all available userland emulation modes. (Actually, only those which
1714     * have CPU support enabled.)
1715     */
1716     void useremul_list_emuls(void)
1717     {
1718     struct syscall_emul *sep;
1719 dpavlin 22 int iadd = DEBUG_INDENTATION * 2;
1720 dpavlin 2
1721     sep = first_syscall_emul;
1722    
1723     if (sep == NULL)
1724     return;
1725    
1726     debug("The following userland-only (syscall) emulation modes are"
1727     " available:\n\n");
1728     debug_indentation(iadd);
1729    
1730     while (sep != NULL) {
1731     if (cpu_family_ptr_by_number(sep->arch) != NULL) {
1732     debug("%s (default CPU \"%s\")\n",
1733     sep->name, sep->cpu_name);
1734     }
1735    
1736     sep = sep->next;
1737     }
1738    
1739     debug_indentation(-iadd);
1740     debug("\n(Most of these modes are bogus.)\n\n");
1741     }
1742    
1743    
1744     /*
1745     * useremul_init():
1746     *
1747     * This function should be called before any other useremul_*() function
1748     * is used.
1749     */
1750     void useremul_init(void)
1751     {
1752     /* Note: These are in reverse alphabetic order: */
1753    
1754     add_useremul("Ultrix", ARCH_MIPS, "R3000",
1755     useremul__ultrix, useremul__ultrix_setup);
1756    
1757     add_useremul("NetBSD/powerpc", ARCH_PPC, "PPC750",
1758     useremul__netbsd, useremul__netbsd_setup);
1759    
1760     add_useremul("NetBSD/pmax", ARCH_MIPS, "R3000",
1761     useremul__netbsd, useremul__netbsd_setup);
1762    
1763 dpavlin 14 add_useremul("NetBSD/arm", ARCH_ARM, "SA1110",
1764 dpavlin 12 useremul__netbsd, useremul__netbsd_setup);
1765    
1766 dpavlin 4 add_useremul("NetBSD/amd64", ARCH_X86, "AMD64",
1767     useremul__netbsd, useremul__netbsd_setup);
1768    
1769 dpavlin 14 add_useremul("NetBSD/alpha", ARCH_ALPHA, "Alpha",
1770     useremul__netbsd, useremul__netbsd_setup);
1771    
1772 dpavlin 2 add_useremul("Linux/PPC64", ARCH_PPC, "PPC970",
1773     useremul__linux, useremul__linux_setup);
1774    
1775 dpavlin 12 add_useremul("FreeBSD/Alpha", ARCH_ALPHA, "Alpha",
1776 dpavlin 2 useremul__freebsd, useremul__freebsd_setup);
1777     }
1778    

  ViewVC Help
Powered by ViewVC 1.1.26