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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26