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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26