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

Contents of /upstream/0.4.1/src/useremul.c

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26