/[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 14 - (hide annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 43578 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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 14 * $Id: useremul.c,v 1.64 2005/08/27 17:29:06 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     * NOTE: The following code should not be CPU arch dependant!
851     * (TODO)
852     */
853    
854     switch (sysnr) {
855    
856     case NETBSD_SYS_exit:
857     debug("[ exit(%i) ]\n", (int)arg0);
858     cpu->running = 0;
859     cpu->machine->exit_without_entering_debugger = 1;
860     break;
861    
862     case NETBSD_SYS_read:
863     debug("[ read(%i,0x%llx,%lli) ]\n",
864     (int)arg0, (long long)arg1, (long long)arg2);
865    
866     if (arg2 != 0) {
867     charbuf = malloc(arg2);
868     if (charbuf == NULL) {
869     fprintf(stderr, "out of memory in "
870     "useremul__netbsd()\n");
871     exit(1);
872     }
873     result_low = read(arg0, charbuf, arg2);
874     if ((int64_t)result_low < 0) {
875     error_code = errno;
876     error_flag = 1;
877     }
878    
879     /* TODO: address validity check */
880     cpu->memory_rw(cpu, cpu->mem, arg1, charbuf,
881     arg2, MEM_WRITE, CACHE_DATA);
882     free(charbuf);
883     }
884     break;
885    
886     case NETBSD_SYS_write:
887     descr = arg0;
888     mipsbuf = arg1;
889     length = arg2;
890     debug("[ write(%i,0x%llx,%lli) ]\n",
891     (int)descr, (long long)mipsbuf, (long long)length);
892     if (length != 0) {
893     charbuf = malloc(length);
894     if (charbuf == NULL) {
895     fprintf(stderr, "out of memory in "
896     "useremul__netbsd()\n");
897     exit(1);
898     }
899     /* TODO: address validity check */
900     cpu->memory_rw(cpu, cpu->mem, mipsbuf, charbuf,
901     length, MEM_READ, CACHE_DATA);
902     result_low = write(descr, charbuf, length);
903     if ((int64_t)result_low < 0) {
904     error_code = errno;
905     error_flag = 1;
906     }
907     free(charbuf);
908     }
909     break;
910    
911     case NETBSD_SYS_open:
912     charbuf = get_userland_string(cpu, arg0);
913     debug("[ open(\"%s\", 0x%llx, 0x%llx) ]\n",
914     charbuf, (long long)arg1, (long long)arg2);
915     result_low = open((char *)charbuf, arg1, arg2);
916     if ((int64_t)result_low < 0) {
917     error_flag = 1;
918     error_code = errno;
919     }
920     free(charbuf);
921     break;
922    
923     case NETBSD_SYS_close:
924     descr = arg0;
925     debug("[ close(%i) ]\n", (int)descr);
926     error_code = close(descr);
927     if (error_code != 0)
928     error_flag = 1;
929     break;
930    
931     case NETBSD_SYS_access:
932     charbuf = get_userland_string(cpu, arg0);
933     debug("[ access(\"%s\", 0x%llx) ]\n",
934     charbuf, (long long) arg1);
935     result_low = access((char *)charbuf, arg1);
936     if (result_low != 0) {
937     error_flag = 1;
938     error_code = errno;
939     }
940     free(charbuf);
941     break;
942    
943     case NETBSD_SYS_getuid:
944 dpavlin 12 result_low = useremul_getuid(cpu);
945 dpavlin 2 break;
946    
947     case NETBSD_SYS_geteuid:
948     debug("[ geteuid() ]\n");
949     result_low = geteuid();
950     break;
951    
952     case NETBSD_SYS_getgid:
953     debug("[ getgid() ]\n");
954     result_low = getgid();
955     break;
956    
957     case NETBSD_SYS_getegid:
958     debug("[ getegid() ]\n");
959     result_low = getegid();
960     break;
961    
962     case NETBSD_SYS_getfsstat:
963     mipsbuf = arg0;
964     length = arg1;
965     flags = arg2;
966     debug("[ getfsstat(0x%llx,%lli,0x%llx) ]\n",
967     (long long)mipsbuf, (long long)length,
968     (long long)flags);
969    
970     result_low = 0; /* nr of mounted filesystems,
971     for now (TODO) */
972    
973     /* Fill in the struct statfs buffer at arg0...
974     copy data from the host's getfsstat(). TODO */
975     #if 1
976     result_low = 1;
977     store_32bit_word(cpu, mipsbuf + 0, 0); /* f_spare2 */
978     store_32bit_word(cpu, mipsbuf + 4, 1024); /* f_bsize */
979     store_32bit_word(cpu, mipsbuf + 8, 65536); /* f_iosize */
980     store_32bit_word(cpu, mipsbuf + 12, 100); /* f_blocks */
981     store_32bit_word(cpu, mipsbuf + 16, 50); /* f_bfree */
982     store_32bit_word(cpu, mipsbuf + 20, 10); /* f_bavail */
983     store_32bit_word(cpu, mipsbuf + 24, 50); /* f_files */
984     store_32bit_word(cpu, mipsbuf + 28, 25); /* f_ffree */
985     store_32bit_word(cpu, mipsbuf + 28, 0x1234); /* f_fsid */
986     store_32bit_word(cpu, mipsbuf + 32, 0); /* f_owner */
987     store_32bit_word(cpu, mipsbuf + 36, 0); /* f_type */
988     store_32bit_word(cpu, mipsbuf + 40, 0); /* f_flags */
989     store_32bit_word(cpu, mipsbuf + 44, 0); /* f_fspare[0] */
990     store_32bit_word(cpu, mipsbuf + 48, 0); /* f_fspare[1] */
991     store_string(cpu, mipsbuf + 52, "ffs"); /* f_typename */
992     #define MFSNAMELEN 16
993     #define MNAMELEN 90
994     store_string(cpu, mipsbuf + 52 + MFSNAMELEN, "/");
995     /* f_mntonname */
996     store_string(cpu, mipsbuf + 52 + MFSNAMELEN + MNAMELEN, "ffs");
997     /* f_mntfromname */
998     #endif
999     break;
1000    
1001     case NETBSD_SYS_break:
1002 dpavlin 12 useremul_break(cpu, arg0);
1003 dpavlin 2 break;
1004    
1005     case NETBSD_SYS_readlink:
1006 dpavlin 12 result_low = useremul_readlink(cpu, &error_code,
1007     arg0, arg1, arg2);
1008 dpavlin 2 break;
1009    
1010     case NETBSD_SYS_sync:
1011 dpavlin 12 useremul_sync(cpu);
1012 dpavlin 2 break;
1013    
1014     case NETBSD_SYS_gettimeofday:
1015     debug("[ gettimeofday(0x%llx,0x%llx) ]\n",
1016     (long long)arg0, (long long)arg1);
1017     result_low = gettimeofday(&tv, &tz);
1018     if (result_low) {
1019     error_flag = 1;
1020     error_code = errno;
1021     } else {
1022     if (arg0 != 0) {
1023     /* Store tv.tv_sec and tv.tv_usec as
1024     'long' (32-bit) values: */
1025     store_32bit_word(cpu, arg0 + 0,
1026     tv.tv_sec);
1027     store_32bit_word(cpu, arg0 + 4,
1028     tv.tv_usec);
1029     }
1030     if (arg1 != 0) {
1031     /* Store tz.tz_minuteswest and
1032     tz.tz_dsttime as 'long'
1033     (32-bit) values: */
1034     store_32bit_word(cpu, arg1 + 0,
1035     tz.tz_minuteswest);
1036     store_32bit_word(cpu, arg1 + 4,
1037     tz.tz_dsttime);
1038     }
1039     }
1040     break;
1041    
1042     case NETBSD_SYS_mmap:
1043     debug("[ mmap(0x%x,%i,%i,%i,%i,0x%llx): TODO ]\n",
1044     arg0, arg1, arg2, arg3, stack0, (long long)stack1);
1045    
1046     if ((int32_t)stack0 == -1) {
1047     /*
1048     * Anonymous allocation:
1049     *
1050     * TODO: Fix this!!!
1051     *
1052     * This quick hack simply allocates anonymous
1053     * mmap memory approximately below the stack.
1054     * This will probably not work with dynamically
1055     * loaded libraries and such.
1056     */
1057     static uint32_t mmap_anon_ptr = 0x70000000;
1058     mmap_anon_ptr -= arg1;
1059     /* round down to page boundary: */
1060     mmap_anon_ptr &= ~4095;
1061     debug("ANON: %i bytes at 0x%08x (TODO: not "
1062     "working yet?)\n", (int)arg1,
1063     mmap_anon_ptr);
1064     result_low = mmap_anon_ptr;
1065     } else {
1066     /* Return NULL for now */
1067     }
1068     break;
1069    
1070     case NETBSD_SYS_dup:
1071     debug("[ dup(%i) ]\n", (int)arg0);
1072     result_low = dup(arg0);
1073     if ((int64_t)result_low < 0) {
1074     error_code = errno;
1075     error_flag = 1;
1076     }
1077     break;
1078    
1079     case NETBSD_SYS_socket:
1080     debug("[ socket(%i,%i,%i) ]\n",
1081     (int)arg0, (int)arg1, (int)arg2);
1082     result_low = socket(arg0,arg1,arg2);
1083     if ((int64_t)result_low < 0) {
1084     error_code = errno;
1085     error_flag = 1;
1086     }
1087     break;
1088    
1089     case NETBSD_SYS_issetugid:
1090     debug("[ issetugid() ]\n");
1091     /* TODO: actually call the real issetugid? */
1092     break;
1093    
1094     case NETBSD_SYS_nanosleep:
1095     debug("[ nanosleep(0x%llx,0x%llx) ]\n",
1096     (long long)arg0, (long long)arg1);
1097    
1098     if (arg0 != 0) {
1099     uint32_t sec = load_32bit_word(cpu, arg0 + 0);
1100     uint32_t nsec = load_32bit_word(cpu, arg0 + 4);
1101     struct timespec ts;
1102     ts.tv_sec = sec;
1103     ts.tv_nsec = nsec;
1104     result_low = nanosleep(&ts, NULL);
1105     if (result_low)
1106     fprintf(stderr, "netbsd emulation "
1107     "nanosleep() failed\n");
1108     /* TODO: arg1 */
1109     } else {
1110     error_flag = 1;
1111     error_code = 14; /* EFAULT */
1112     }
1113     break;
1114    
1115     case NETBSD_SYS___fstat13:
1116     debug("[ __fstat13(%lli,0x%llx): TODO ]\n",
1117     (long long)arg0, (long long)arg1);
1118     error_flag = 1;
1119     error_code = 9; /* EBADF */
1120     break;
1121    
1122     case NETBSD_SYS___getcwd:
1123     debug("[ __getcwd(0x%llx,%lli): TODO ]\n",
1124     (long long)arg0, (long long)arg1);
1125     if (arg1 != 0 && arg1 < 500000) {
1126     char *buf = malloc(arg1);
1127     unsigned int i;
1128    
1129     getcwd(buf, arg1);
1130    
1131     /* zero-terminate in host's space: */
1132     buf[arg1 - 1] = 0;
1133    
1134     for (i = 0; i<arg1 && i < arg1; i++)
1135     cpu->memory_rw(cpu, cpu->mem, arg0 + i,
1136     (unsigned char *)&buf[i], 1,
1137     MEM_WRITE, CACHE_NONE);
1138    
1139     /* zero-terminate in emulated space: */
1140     cpu->memory_rw(cpu, cpu->mem, arg0 + arg1-1,
1141     (unsigned char *)&buf[arg1 - 1],
1142     1, MEM_WRITE, CACHE_NONE);
1143    
1144     free(buf);
1145     }
1146     result_low = arg0;
1147     break;
1148    
1149     case NETBSD_SYS___sigaction14:
1150     debug("[ __sigaction14(%lli,0x%llx,0x%llx): TODO ]\n",
1151     (long long)arg0, (long long)arg1, (long long)arg2);
1152     error_flag = 1;
1153     error_code = 9; /* EBADF */
1154     break;
1155    
1156     case NETBSD_SYS___sysctl:
1157     sysctl_name = arg0;
1158     sysctl_namelen = arg1;
1159     sysctl_oldp = arg2;
1160     sysctl_oldlenp = arg3;
1161     sysctl_newp = load_32bit_word(cpu,
1162     cpu->cd.mips.gpr[MIPS_GPR_SP]);
1163     /* TODO: +4 and +8 ?? */
1164     sysctl_newlen = load_32bit_word(cpu,
1165     cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
1166     debug("[ __sysctl(");
1167    
1168     name0 = load_32bit_word(cpu, sysctl_name + 0);
1169     name1 = load_32bit_word(cpu, sysctl_name + 4);
1170     name2 = load_32bit_word(cpu, sysctl_name + 8);
1171     name3 = load_32bit_word(cpu, sysctl_name + 12);
1172     debug("name (@ 0x%08x) = %i, %i, %i, %i) ]\n",
1173     sysctl_name, name0, name1, name2, name3);
1174    
1175     if (name0 == CTL_KERN && name1 == KERN_HOSTNAME) {
1176     char hname[256];
1177     hname[0] = '\0';
1178     gethostname(hname, sizeof(hname));
1179     hname[sizeof(hname)-1] = '\0';
1180     if (sysctl_oldp != 0)
1181     store_string(cpu, sysctl_oldp, hname);
1182     if (sysctl_oldlenp != 0)
1183     store_32bit_word(cpu, sysctl_oldlenp,
1184     strlen(hname));
1185     } else if (name0 == CTL_HW && name1 == HW_PAGESIZE) {
1186     if (sysctl_oldp != 0)
1187     store_32bit_word(cpu,
1188     sysctl_oldp, 4096);
1189     if (sysctl_oldlenp != 0)
1190     store_32bit_word(cpu,
1191     sysctl_oldlenp, sizeof(uint32_t));
1192     } else {
1193     error_flag = 1;
1194     error_code = 2; /* ENOENT */
1195     }
1196     break;
1197    
1198     default:
1199     fatal("[ UNIMPLEMENTED netbsd syscall %i ]\n", sysnr);
1200     error_flag = 1;
1201     error_code = 78; /* ENOSYS */
1202     }
1203    
1204    
1205     switch (cpu->machine->arch) {
1206 dpavlin 14 case ARCH_ARM:
1207     /* NetBSD/arm return values: */
1208     cpu->cd.arm.r[0] = result_low;
1209     cpu->cd.arm.cpsr &= ~ARM_FLAG_C;
1210     if (error_flag) {
1211     cpu->cd.arm.cpsr |= ARM_FLAG_C;
1212     cpu->cd.arm.r[0] = error_code;
1213     }
1214     if (result_high_set)
1215     cpu->cd.arm.r[1] = result_high;
1216     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