/[gxemul]/trunk/src/useremul.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Annotation of /trunk/src/useremul.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (hide annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 37106 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 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