/[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 18 - (hide annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 43571 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26