/[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 36 - (hide annotations)
Mon Oct 8 16:21:34 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 43974 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1497 2007/03/18 03:41:36 debug Exp $
20070224	Minor update to the initialization of the ns16550 in
		machine_walnut.c, to allow that machine type to boot with the
		new interrupt system (although it is still a dummy machine).
		Adding a wdc at 0x14000000 to machine_landisk.c, and fixing
		the SCIF serial interrupts of the SH4 cpu enough to get
		NetBSD/landisk booting from a disk image :-)  Adding a
		preliminary install instruction skeleton to guestoses.html.
20070306	Adding SH-IPL+G PROM emulation, and also passing the "end"
		symbol in r5 on bootup, for Landisk emulation. This is enough
		to get OpenBSD/landisk to install :)  Adding a preliminary
		install instruction skeleton to the documentation. SuperH
		emulation is still shaky, though :-/
20070307	Fixed a strangeness in memory_sh.c (read/write was never
		returned for any page). (Unknown whether this fixes any actual
		problems, though.)
20070308	dev_ram.c fix: invalidate code translations on writes to
		RAM, emulated as separate devices. Linux/dreamcast gets
		further in the boot process than before, but still bugs out
		in userland.
		Fixing bugs in the "stc.l gbr,@-rN" and "ldc.l @rN+,gbr" SuperH 
		instructions (they should NOT check the MD bit), allowing the
		Linux/dreamcast Live CD to reach userland correctly :-)
20070310	Changing the cpu name "Alpha" in src/useremul.c to "21364" to
		unbreak userland syscall emulation of FreeBSD/Alpha binaries.
20070314	Applying a patch from Michael Yaroslavtsev which fixes the
		previous Linux lib64 patch to the configure script.
20070315	Adding a (dummy) sun4v machine type, and SPARC T1 cpu type.
20070316	Creating a new directory, src/disk, and moving diskimage.c
		to it. Separating out bootblock loading stuff from emul.c into
		new files in src/disk.
		Adding some more SPARC registers.
20070318	Preparing/testing for a minirelease, 0.4.4.1.

==============  RELEASE 0.4.4.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26