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

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


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

  ViewVC Help
Powered by ViewVC 1.1.26