/[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 28 - (hide annotations)
Mon Oct 8 16:20:26 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 43983 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1298 2006/07/22 11:27:46 debug Exp $
20060626	Continuing on SPARC emulation (beginning on the 'save'
		instruction, register windows, etc).
20060629	Planning statistics gathering (new -s command line option),
		and renaming speed_tricks to allow_instruction_combinations.
20060630	Some minor manual page updates.
		Various cleanups.
		Implementing the -s command line option.
20060701	FINALLY found the bug which prevented Linux and Ultrix from
		running without the ugly hack in the R2000/R3000 cache isol
		code; it was the phystranslation hint array which was buggy.
		Removing the phystranslation hint code completely, for now.
20060702	Minor dyntrans cleanups; invalidation of physpages now only
		invalidate those parts of a page that have actually been
		translated. (32 parts per page.)
		Some MIPS non-R3000 speed fixes.
		Experimenting with MIPS instruction combination for some
		addiu+bne+sw loops, and sw+sw+sw.
		Adding support (again) for larger-than-4KB pages in MIPS tlbw*.
		Continuing on SPARC emulation: adding load/store instructions.
20060704	Fixing a virtual vs physical page shift bug in the new tlbw*
		implementation. Problem noticed by Jakub Jermar. (Many thanks.)
		Moving rfe and eret to cpu_mips_instr.c, since that is the
		only place that uses them nowadays.
20060705	Removing the BSD license from the "testmachine" include files,
		placing them in the public domain instead; this enables the
		testmachine stuff to be used from projects which are
		incompatible with the BSD license for some reason.
20060707	Adding instruction combinations for the R2000/R3000 L1
		I-cache invalidation code used by NetBSD/pmax 3.0, lui+addiu,
		various branches followed by addiu or nop, and jr ra followed
		by addiu. The time it takes to perform a full NetBSD/pmax R3000
		install on the laptop has dropped from 573 seconds to 539. :-)
20060708	Adding a framebuffer controller device (dev_fbctrl), which so
		far can be used to change the fb resolution during runtime, but
		in the future will also be useful for accelerated block fill/
		copy, and possibly also simplified character output.
		Adding an instruction combination for NetBSD/pmax' strlen.
20060709	Minor fixes: reading raw files in src/file.c wasn't memblock
		aligned, removing buggy multi_sw MIPS instruction combination,
		etc.
20060711	Adding a machine_qemu.c, which contains a "qemu_mips" machine.
		(It mimics QEMU's MIPS machine mode, so that a test kernel
		made for QEMU_MIPS also can run in GXemul... at least to some
		extent.)  Adding a short section about how to run this mode to
		doc/guestoses.html.
20060714	Misc. minor code cleanups.
20060715	Applying a patch which adds getchar() to promemul/yamon.c
		(from Oleksandr Tymoshenko).
		Adding yamon.h from NetBSD, and rewriting yamon.c to use it
		(instead of ugly hardcoded numbers) + some cleanup.
20060716	Found and fixed the bug which broke single-stepping of 64-bit
		programs between 0.4.0 and 0.4.0.1 (caused by too quick
		refactoring and no testing). Hopefully this fix will not
		break too many other things.
20060718	Continuing on the 8253 PIT; it now works with Linux/QEMU_MIPS.
		Re-adding the sw+sw+sw instr comb (the problem was that I had
		ignored endian issues); however, it doesn't seem to give any
		big performance gain.
20060720	Adding a dummy Transputer mode (T414, T800 etc) skeleton (only
		the 'j' and 'ldc' instructions are implemented so far). :-}
20060721	Adding gtreg.h from NetBSD, updating dev_gt.c to use it, plus
		misc. other updates to get Linux 2.6 for evbmips/malta working
		(thanks to Alec Voropay for the details).
		FINALLY found and fixed the bug which made tlbw* for non-R3000
		buggy; it was a reference count problem in the dyntrans core.
20060722	Testing stuff; things seem stable enough for a new release.

==============  RELEASE 0.4.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26