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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26