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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 17 - (show annotations)
Mon Oct 8 16:19:05 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 43578 byte(s)
0.3.6.1
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.64 2005/08/27 17:29:06 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: The following code should not be CPU arch dependant!
851 * (TODO)
852 */
853
854 switch (sysnr) {
855
856 case NETBSD_SYS_exit:
857 debug("[ exit(%i) ]\n", (int)arg0);
858 cpu->running = 0;
859 cpu->machine->exit_without_entering_debugger = 1;
860 break;
861
862 case NETBSD_SYS_read:
863 debug("[ read(%i,0x%llx,%lli) ]\n",
864 (int)arg0, (long long)arg1, (long long)arg2);
865
866 if (arg2 != 0) {
867 charbuf = malloc(arg2);
868 if (charbuf == NULL) {
869 fprintf(stderr, "out of memory in "
870 "useremul__netbsd()\n");
871 exit(1);
872 }
873 result_low = read(arg0, charbuf, arg2);
874 if ((int64_t)result_low < 0) {
875 error_code = errno;
876 error_flag = 1;
877 }
878
879 /* TODO: address validity check */
880 cpu->memory_rw(cpu, cpu->mem, arg1, charbuf,
881 arg2, MEM_WRITE, CACHE_DATA);
882 free(charbuf);
883 }
884 break;
885
886 case NETBSD_SYS_write:
887 descr = arg0;
888 mipsbuf = arg1;
889 length = arg2;
890 debug("[ write(%i,0x%llx,%lli) ]\n",
891 (int)descr, (long long)mipsbuf, (long long)length);
892 if (length != 0) {
893 charbuf = malloc(length);
894 if (charbuf == NULL) {
895 fprintf(stderr, "out of memory in "
896 "useremul__netbsd()\n");
897 exit(1);
898 }
899 /* TODO: address validity check */
900 cpu->memory_rw(cpu, cpu->mem, mipsbuf, charbuf,
901 length, MEM_READ, CACHE_DATA);
902 result_low = write(descr, charbuf, length);
903 if ((int64_t)result_low < 0) {
904 error_code = errno;
905 error_flag = 1;
906 }
907 free(charbuf);
908 }
909 break;
910
911 case NETBSD_SYS_open:
912 charbuf = get_userland_string(cpu, arg0);
913 debug("[ open(\"%s\", 0x%llx, 0x%llx) ]\n",
914 charbuf, (long long)arg1, (long long)arg2);
915 result_low = open((char *)charbuf, arg1, arg2);
916 if ((int64_t)result_low < 0) {
917 error_flag = 1;
918 error_code = errno;
919 }
920 free(charbuf);
921 break;
922
923 case NETBSD_SYS_close:
924 descr = arg0;
925 debug("[ close(%i) ]\n", (int)descr);
926 error_code = close(descr);
927 if (error_code != 0)
928 error_flag = 1;
929 break;
930
931 case NETBSD_SYS_access:
932 charbuf = get_userland_string(cpu, arg0);
933 debug("[ access(\"%s\", 0x%llx) ]\n",
934 charbuf, (long long) arg1);
935 result_low = access((char *)charbuf, arg1);
936 if (result_low != 0) {
937 error_flag = 1;
938 error_code = errno;
939 }
940 free(charbuf);
941 break;
942
943 case NETBSD_SYS_getuid:
944 result_low = useremul_getuid(cpu);
945 break;
946
947 case NETBSD_SYS_geteuid:
948 debug("[ geteuid() ]\n");
949 result_low = geteuid();
950 break;
951
952 case NETBSD_SYS_getgid:
953 debug("[ getgid() ]\n");
954 result_low = getgid();
955 break;
956
957 case NETBSD_SYS_getegid:
958 debug("[ getegid() ]\n");
959 result_low = getegid();
960 break;
961
962 case NETBSD_SYS_getfsstat:
963 mipsbuf = arg0;
964 length = arg1;
965 flags = arg2;
966 debug("[ getfsstat(0x%llx,%lli,0x%llx) ]\n",
967 (long long)mipsbuf, (long long)length,
968 (long long)flags);
969
970 result_low = 0; /* nr of mounted filesystems,
971 for now (TODO) */
972
973 /* Fill in the struct statfs buffer at arg0...
974 copy data from the host's getfsstat(). TODO */
975 #if 1
976 result_low = 1;
977 store_32bit_word(cpu, mipsbuf + 0, 0); /* f_spare2 */
978 store_32bit_word(cpu, mipsbuf + 4, 1024); /* f_bsize */
979 store_32bit_word(cpu, mipsbuf + 8, 65536); /* f_iosize */
980 store_32bit_word(cpu, mipsbuf + 12, 100); /* f_blocks */
981 store_32bit_word(cpu, mipsbuf + 16, 50); /* f_bfree */
982 store_32bit_word(cpu, mipsbuf + 20, 10); /* f_bavail */
983 store_32bit_word(cpu, mipsbuf + 24, 50); /* f_files */
984 store_32bit_word(cpu, mipsbuf + 28, 25); /* f_ffree */
985 store_32bit_word(cpu, mipsbuf + 28, 0x1234); /* f_fsid */
986 store_32bit_word(cpu, mipsbuf + 32, 0); /* f_owner */
987 store_32bit_word(cpu, mipsbuf + 36, 0); /* f_type */
988 store_32bit_word(cpu, mipsbuf + 40, 0); /* f_flags */
989 store_32bit_word(cpu, mipsbuf + 44, 0); /* f_fspare[0] */
990 store_32bit_word(cpu, mipsbuf + 48, 0); /* f_fspare[1] */
991 store_string(cpu, mipsbuf + 52, "ffs"); /* f_typename */
992 #define MFSNAMELEN 16
993 #define MNAMELEN 90
994 store_string(cpu, mipsbuf + 52 + MFSNAMELEN, "/");
995 /* f_mntonname */
996 store_string(cpu, mipsbuf + 52 + MFSNAMELEN + MNAMELEN, "ffs");
997 /* f_mntfromname */
998 #endif
999 break;
1000
1001 case NETBSD_SYS_break:
1002 useremul_break(cpu, arg0);
1003 break;
1004
1005 case NETBSD_SYS_readlink:
1006 result_low = useremul_readlink(cpu, &error_code,
1007 arg0, arg1, arg2);
1008 break;
1009
1010 case NETBSD_SYS_sync:
1011 useremul_sync(cpu);
1012 break;
1013
1014 case NETBSD_SYS_gettimeofday:
1015 debug("[ gettimeofday(0x%llx,0x%llx) ]\n",
1016 (long long)arg0, (long long)arg1);
1017 result_low = gettimeofday(&tv, &tz);
1018 if (result_low) {
1019 error_flag = 1;
1020 error_code = errno;
1021 } else {
1022 if (arg0 != 0) {
1023 /* Store tv.tv_sec and tv.tv_usec as
1024 'long' (32-bit) values: */
1025 store_32bit_word(cpu, arg0 + 0,
1026 tv.tv_sec);
1027 store_32bit_word(cpu, arg0 + 4,
1028 tv.tv_usec);
1029 }
1030 if (arg1 != 0) {
1031 /* Store tz.tz_minuteswest and
1032 tz.tz_dsttime as 'long'
1033 (32-bit) values: */
1034 store_32bit_word(cpu, arg1 + 0,
1035 tz.tz_minuteswest);
1036 store_32bit_word(cpu, arg1 + 4,
1037 tz.tz_dsttime);
1038 }
1039 }
1040 break;
1041
1042 case NETBSD_SYS_mmap:
1043 debug("[ mmap(0x%x,%i,%i,%i,%i,0x%llx): TODO ]\n",
1044 arg0, arg1, arg2, arg3, stack0, (long long)stack1);
1045
1046 if ((int32_t)stack0 == -1) {
1047 /*
1048 * Anonymous allocation:
1049 *
1050 * TODO: Fix this!!!
1051 *
1052 * This quick hack simply allocates anonymous
1053 * mmap memory approximately below the stack.
1054 * This will probably not work with dynamically
1055 * loaded libraries and such.
1056 */
1057 static uint32_t mmap_anon_ptr = 0x70000000;
1058 mmap_anon_ptr -= arg1;
1059 /* round down to page boundary: */
1060 mmap_anon_ptr &= ~4095;
1061 debug("ANON: %i bytes at 0x%08x (TODO: not "
1062 "working yet?)\n", (int)arg1,
1063 mmap_anon_ptr);
1064 result_low = mmap_anon_ptr;
1065 } else {
1066 /* Return NULL for now */
1067 }
1068 break;
1069
1070 case NETBSD_SYS_dup:
1071 debug("[ dup(%i) ]\n", (int)arg0);
1072 result_low = dup(arg0);
1073 if ((int64_t)result_low < 0) {
1074 error_code = errno;
1075 error_flag = 1;
1076 }
1077 break;
1078
1079 case NETBSD_SYS_socket:
1080 debug("[ socket(%i,%i,%i) ]\n",
1081 (int)arg0, (int)arg1, (int)arg2);
1082 result_low = socket(arg0,arg1,arg2);
1083 if ((int64_t)result_low < 0) {
1084 error_code = errno;
1085 error_flag = 1;
1086 }
1087 break;
1088
1089 case NETBSD_SYS_issetugid:
1090 debug("[ issetugid() ]\n");
1091 /* TODO: actually call the real issetugid? */
1092 break;
1093
1094 case NETBSD_SYS_nanosleep:
1095 debug("[ nanosleep(0x%llx,0x%llx) ]\n",
1096 (long long)arg0, (long long)arg1);
1097
1098 if (arg0 != 0) {
1099 uint32_t sec = load_32bit_word(cpu, arg0 + 0);
1100 uint32_t nsec = load_32bit_word(cpu, arg0 + 4);
1101 struct timespec ts;
1102 ts.tv_sec = sec;
1103 ts.tv_nsec = nsec;
1104 result_low = nanosleep(&ts, NULL);
1105 if (result_low)
1106 fprintf(stderr, "netbsd emulation "
1107 "nanosleep() failed\n");
1108 /* TODO: arg1 */
1109 } else {
1110 error_flag = 1;
1111 error_code = 14; /* EFAULT */
1112 }
1113 break;
1114
1115 case NETBSD_SYS___fstat13:
1116 debug("[ __fstat13(%lli,0x%llx): TODO ]\n",
1117 (long long)arg0, (long long)arg1);
1118 error_flag = 1;
1119 error_code = 9; /* EBADF */
1120 break;
1121
1122 case NETBSD_SYS___getcwd:
1123 debug("[ __getcwd(0x%llx,%lli): TODO ]\n",
1124 (long long)arg0, (long long)arg1);
1125 if (arg1 != 0 && arg1 < 500000) {
1126 char *buf = malloc(arg1);
1127 unsigned int i;
1128
1129 getcwd(buf, arg1);
1130
1131 /* zero-terminate in host's space: */
1132 buf[arg1 - 1] = 0;
1133
1134 for (i = 0; i<arg1 && i < arg1; i++)
1135 cpu->memory_rw(cpu, cpu->mem, arg0 + i,
1136 (unsigned char *)&buf[i], 1,
1137 MEM_WRITE, CACHE_NONE);
1138
1139 /* zero-terminate in emulated space: */
1140 cpu->memory_rw(cpu, cpu->mem, arg0 + arg1-1,
1141 (unsigned char *)&buf[arg1 - 1],
1142 1, MEM_WRITE, CACHE_NONE);
1143
1144 free(buf);
1145 }
1146 result_low = arg0;
1147 break;
1148
1149 case NETBSD_SYS___sigaction14:
1150 debug("[ __sigaction14(%lli,0x%llx,0x%llx): TODO ]\n",
1151 (long long)arg0, (long long)arg1, (long long)arg2);
1152 error_flag = 1;
1153 error_code = 9; /* EBADF */
1154 break;
1155
1156 case NETBSD_SYS___sysctl:
1157 sysctl_name = arg0;
1158 sysctl_namelen = arg1;
1159 sysctl_oldp = arg2;
1160 sysctl_oldlenp = arg3;
1161 sysctl_newp = load_32bit_word(cpu,
1162 cpu->cd.mips.gpr[MIPS_GPR_SP]);
1163 /* TODO: +4 and +8 ?? */
1164 sysctl_newlen = load_32bit_word(cpu,
1165 cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
1166 debug("[ __sysctl(");
1167
1168 name0 = load_32bit_word(cpu, sysctl_name + 0);
1169 name1 = load_32bit_word(cpu, sysctl_name + 4);
1170 name2 = load_32bit_word(cpu, sysctl_name + 8);
1171 name3 = load_32bit_word(cpu, sysctl_name + 12);
1172 debug("name (@ 0x%08x) = %i, %i, %i, %i) ]\n",
1173 sysctl_name, name0, name1, name2, name3);
1174
1175 if (name0 == CTL_KERN && name1 == KERN_HOSTNAME) {
1176 char hname[256];
1177 hname[0] = '\0';
1178 gethostname(hname, sizeof(hname));
1179 hname[sizeof(hname)-1] = '\0';
1180 if (sysctl_oldp != 0)
1181 store_string(cpu, sysctl_oldp, hname);
1182 if (sysctl_oldlenp != 0)
1183 store_32bit_word(cpu, sysctl_oldlenp,
1184 strlen(hname));
1185 } else if (name0 == CTL_HW && name1 == HW_PAGESIZE) {
1186 if (sysctl_oldp != 0)
1187 store_32bit_word(cpu,
1188 sysctl_oldp, 4096);
1189 if (sysctl_oldlenp != 0)
1190 store_32bit_word(cpu,
1191 sysctl_oldlenp, sizeof(uint32_t));
1192 } else {
1193 error_flag = 1;
1194 error_code = 2; /* ENOENT */
1195 }
1196 break;
1197
1198 default:
1199 fatal("[ UNIMPLEMENTED netbsd syscall %i ]\n", sysnr);
1200 error_flag = 1;
1201 error_code = 78; /* ENOSYS */
1202 }
1203
1204
1205 switch (cpu->machine->arch) {
1206 case ARCH_ARM:
1207 /* NetBSD/arm return values: */
1208 cpu->cd.arm.r[0] = result_low;
1209 cpu->cd.arm.cpsr &= ~ARM_FLAG_C;
1210 if (error_flag) {
1211 cpu->cd.arm.cpsr |= ARM_FLAG_C;
1212 cpu->cd.arm.r[0] = error_code;
1213 }
1214 if (result_high_set)
1215 cpu->cd.arm.r[1] = result_high;
1216 break;
1217 case ARCH_MIPS:
1218 /*
1219 * NetBSD/mips return values:
1220 *
1221 * a3 is 0 if the syscall was ok, otherwise 1.
1222 * v0 (and sometimes v1) contain the result value.
1223 */
1224 cpu->cd.mips.gpr[MIPS_GPR_A3] = error_flag;
1225 if (error_flag)
1226 cpu->cd.mips.gpr[MIPS_GPR_V0] = error_code;
1227 else
1228 cpu->cd.mips.gpr[MIPS_GPR_V0] = result_low;
1229
1230 if (result_high_set)
1231 cpu->cd.mips.gpr[MIPS_GPR_V1] = result_high;
1232 break;
1233 case ARCH_PPC:
1234 /*
1235 * NetBSD/powerpc return values:
1236 *
1237 * TODO
1238 */
1239 cpu->cd.ppc.gpr[3] = result_low;
1240
1241 if (result_high_set)
1242 cpu->cd.ppc.gpr[4] = result_high;
1243 break;
1244 }
1245 }
1246
1247
1248 /*
1249 * useremul__ultrix():
1250 *
1251 * Ultrix syscall emulation.
1252 */
1253 static void useremul__ultrix(struct cpu *cpu, uint32_t code)
1254 {
1255 int error_flag = 0, result_high_set = 0;
1256 uint64_t arg0,arg1,arg2,arg3,stack0=0,stack1=0,stack2;
1257 int sysnr = 0;
1258 int64_t error_code = 0;
1259 uint64_t result_low = 0;
1260 uint64_t result_high = 0;
1261 struct timeval tv;
1262 struct timezone tz;
1263 int descr;
1264 uint64_t length, mipsbuf;
1265 unsigned char *charbuf;
1266
1267 /*
1268 * Ultrix/pmax gets the syscall number in register v0,
1269 * and syscall arguments in registers a0, a1, ...
1270 *
1271 * TODO: If there is a __syscall-like syscall (as in NetBSD)
1272 * then 64-bit args may be passed in two registers or something...
1273 * If so, then copy from the section above (NetBSD).
1274 */
1275 sysnr = cpu->cd.mips.gpr[MIPS_GPR_V0];
1276
1277 arg0 = cpu->cd.mips.gpr[MIPS_GPR_A0];
1278 arg1 = cpu->cd.mips.gpr[MIPS_GPR_A1];
1279 arg2 = cpu->cd.mips.gpr[MIPS_GPR_A2];
1280 arg3 = cpu->cd.mips.gpr[MIPS_GPR_A3];
1281 /* TODO: stack arguments? Are these correct? */
1282 stack0 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 0);
1283 stack1 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
1284 stack2 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 8);
1285
1286 switch (sysnr) {
1287
1288 case ULTRIX_SYS_exit:
1289 debug("[ exit(%i) ]\n", (int)arg0);
1290 cpu->running = 0;
1291 cpu->machine->exit_without_entering_debugger = 1;
1292 break;
1293
1294 case ULTRIX_SYS_read:
1295 debug("[ read(%i,0x%llx,%lli) ]\n",
1296 (int)arg0, (long long)arg1, (long long)arg2);
1297
1298 if (arg2 != 0) {
1299 charbuf = malloc(arg2);
1300 if (charbuf == NULL) {
1301 fprintf(stderr, "out of memory in "
1302 "useremul__ultrix()\n");
1303 exit(1);
1304 }
1305
1306 result_low = read(arg0, charbuf, arg2);
1307 if ((int64_t)result_low < 0) {
1308 error_code = errno;
1309 error_flag = 1;
1310 }
1311
1312 /* TODO: address validity check */
1313 cpu->memory_rw(cpu, cpu->mem, arg1, charbuf,
1314 arg2, MEM_WRITE, CACHE_DATA);
1315
1316 free(charbuf);
1317 }
1318 break;
1319
1320 case ULTRIX_SYS_write:
1321 descr = arg0;
1322 mipsbuf = arg1;
1323 length = arg2;
1324 debug("[ write(%i,0x%llx,%lli) ]\n",
1325 (int)descr, (long long)mipsbuf, (long long)length);
1326
1327 if (length != 0) {
1328 charbuf = malloc(length);
1329 if (charbuf == NULL) {
1330 fprintf(stderr, "out of memory in "
1331 "useremul__ultrix()\n");
1332 exit(1);
1333 }
1334
1335 /* TODO: address validity check */
1336 cpu->memory_rw(cpu, cpu->mem, mipsbuf, charbuf,
1337 length, MEM_READ, CACHE_DATA);
1338
1339 result_low = write(descr, charbuf, length);
1340 if ((int64_t)result_low < 0) {
1341 error_code = errno;
1342 error_flag = 1;
1343 }
1344 free(charbuf);
1345 }
1346 break;
1347
1348 case ULTRIX_SYS_open:
1349 charbuf = get_userland_string(cpu, arg0);
1350 debug("[ open(\"%s\", 0x%llx, 0x%llx) ]\n",
1351 charbuf, (long long)arg1, (long long)arg2);
1352
1353 result_low = open((char *)charbuf, arg1, arg2);
1354 if ((int64_t)result_low < 0) {
1355 error_flag = 1;
1356 error_code = errno;
1357 }
1358 free(charbuf);
1359 break;
1360
1361 case ULTRIX_SYS_close:
1362 descr = arg0;
1363 debug("[ close(%i) ]\n", (int)descr);
1364
1365 /* Special case because some Ultrix programs tend
1366 to close low descriptors: */
1367 if (descr <= 2) {
1368 error_flag = 1;
1369 error_code = 2; /* TODO: Ultrix ENOENT error code */
1370 break;
1371 }
1372
1373 error_code = close(descr);
1374 if (error_code != 0)
1375 error_flag = 1;
1376 break;
1377
1378 case ULTRIX_SYS_break:
1379 useremul_break(cpu, arg0);
1380 break;
1381
1382 case ULTRIX_SYS_sync:
1383 useremul_sync(cpu);
1384 break;
1385
1386 case ULTRIX_SYS_getuid:
1387 result_low = useremul_getuid(cpu);
1388 break;
1389
1390 case ULTRIX_SYS_getgid:
1391 debug("[ getgid() ]\n");
1392 result_low = getgid();
1393 break;
1394
1395 case ULTRIX_SYS_dup:
1396 debug("[ dup(%i) ]\n", (int)arg0);
1397 result_low = dup(arg0);
1398 if ((int64_t)result_low < 0) {
1399 error_code = errno;
1400 error_flag = 1;
1401 }
1402 break;
1403
1404 case ULTRIX_SYS_socket:
1405 debug("[ socket(%i,%i,%i) ]\n",
1406 (int)arg0, (int)arg1, (int)arg2);
1407 result_low = socket(arg0,arg1,arg2);
1408 if ((int64_t)result_low < 0) {
1409 error_code = errno;
1410 error_flag = 1;
1411 }
1412 break;
1413
1414 case ULTRIX_SYS_select:
1415 debug("[ select(%i,0x%x,0x%x,0x%x,0x%x): TODO ]\n",
1416 (int)arg0, (int)arg1, (int)arg2, (int)arg3, (int)stack0);
1417
1418 /* TODO */
1419 {
1420 fd_set fdset;
1421 FD_SET(3, &fdset);
1422 result_low = select(4, &fdset, NULL, NULL, NULL);
1423 }
1424 break;
1425
1426 case ULTRIX_SYS_setsockopt:
1427 debug("[ setsockopt(%i,%i,%i,0x%x,%i): TODO ]\n",
1428 (int)arg0, (int)arg1, (int)arg2, (int)arg3, (int)stack0);
1429 /* TODO: len is not 4, len is stack0? */
1430 charbuf = get_userland_buf(cpu, arg3, 4);
1431 /* TODO: endianness of charbuf, etc */
1432 result_low = setsockopt(arg0, arg1, arg2, (void *)charbuf, 4);
1433 if ((int64_t)result_low < 0) {
1434 error_code = errno;
1435 error_flag = 1;
1436 }
1437 free(charbuf);
1438 printf("setsockopt!!!! res = %i error=%i\n",
1439 (int)result_low, (int)error_code);
1440 break;
1441
1442 case ULTRIX_SYS_connect:
1443 debug("[ connect(%i,0x%x,%i) ]\n",
1444 (int)arg0, (int)arg1, (int)arg2);
1445 charbuf = get_userland_buf(cpu, arg1, arg2);
1446 result_low = connect(arg0, (void *)charbuf, arg2);
1447 if ((int64_t)result_low < 0) {
1448 error_code = errno;
1449 error_flag = 1;
1450 }
1451 printf("connect!!!! res = %i error=%i\n",
1452 (int)result_low, (int)error_code);
1453 free(charbuf);
1454 break;
1455
1456 case ULTRIX_SYS_fcntl:
1457 debug("[ fcntl(%i,%i,0x%x): TODO ]\n",
1458 (int)arg0, (int)arg1, (int)arg2);
1459 /* TODO: how about that third argument? */
1460 result_low = fcntl(arg0, arg1, arg2);
1461 if ((int64_t)result_low < 0) {
1462 error_code = errno;
1463 error_flag = 1;
1464 }
1465 printf("fcntl!!!! res = %i error=%i\n",
1466 (int)result_low, (int)error_code);
1467 break;
1468
1469 case ULTRIX_SYS_stat43:
1470 charbuf = get_userland_string(cpu, arg0);
1471 debug("[ stat(\"%s\", 0x%llx): TODO ]\n",
1472 charbuf, (long long)arg1);
1473
1474 if (arg1 != 0) {
1475 struct stat st;
1476 result_low = stat((char *)charbuf, &st);
1477 if ((int64_t)result_low < 0) {
1478 error_flag = 1;
1479 error_code = errno;
1480 } else {
1481 /* Fill in the Ultrix stat struct at arg1: */
1482
1483 /* TODO */
1484 }
1485 } else {
1486 error_flag = 1;
1487 error_code = 1111; /* TODO: ultrix ENOMEM? */
1488 }
1489 free(charbuf);
1490 break;
1491
1492 case ULTRIX_SYS_fstat:
1493 result_low = useremul_fstat(cpu, &error_code, arg0, arg1);
1494 break;
1495
1496 case ULTRIX_SYS_getpagesize:
1497 debug("[ getpagesize() ]\n");
1498 result_low = 4096;
1499 break;
1500
1501 case ULTRIX_SYS_getdtablesize:
1502 debug("[ getdtablesize() ]\n");
1503 result_low = getdtablesize();
1504 break;
1505
1506 case ULTRIX_SYS_gethostname:
1507 debug("[ gethostname(0x%llx,%lli) ]\n",
1508 (long long)arg0, (long long)arg1);
1509 result_low = 0;
1510 if (arg1 != 0 && arg1 < 500000) {
1511 unsigned char *buf = malloc(arg1);
1512 unsigned int i;
1513
1514 result_low = gethostname((char *)buf, arg1);
1515 for (i = 0; i<arg1 && i < arg1; i++)
1516 cpu->memory_rw(cpu, cpu->mem, arg0 + i,
1517 &buf[i], 1, MEM_WRITE, CACHE_NONE);
1518
1519 free(buf);
1520 } else {
1521 error_flag = 1;
1522 error_code = 5555; /* TODO */ /* ENOMEM */
1523 }
1524 break;
1525
1526 case ULTRIX_SYS_writev:
1527 descr = arg0;
1528 debug("[ writev(%lli,0x%llx,%lli) ]\n",
1529 (long long)arg0, (long long)arg1, (long long)arg2);
1530
1531 if (arg1 != 0) {
1532 unsigned int i, total = 0;
1533
1534 for (i=0; i<arg2; i++) {
1535 uint32_t iov_base, iov_len;
1536 iov_base = load_32bit_word(cpu,
1537 arg1 + 8*i + 0); /* char * */
1538 iov_len = load_32bit_word(cpu,
1539 arg1 + 8*i + 4); /* size_t */
1540
1541 if (iov_len != 0) {
1542 unsigned char *charbuf =
1543 malloc(iov_len);
1544 if (charbuf == NULL) {
1545 fprintf(stderr, "out of memory"
1546 " in useremul__ultrix()\n");
1547 exit(1);
1548 }
1549
1550 /* TODO: address validity check */
1551 cpu->memory_rw(cpu, cpu->mem, (uint64_t)
1552 iov_base, charbuf, iov_len,
1553 MEM_READ, CACHE_DATA);
1554 total += write(descr, charbuf, iov_len);
1555 free(charbuf);
1556 }
1557 }
1558
1559 result_low = total;
1560 }
1561 break;
1562
1563 case ULTRIX_SYS_gethostid:
1564 debug("[ gethostid() ]\n");
1565 /* This is supposed to return a unique 32-bit host id. */
1566 result_low = 0x12345678;
1567 break;
1568
1569 case ULTRIX_SYS_gettimeofday:
1570 debug("[ gettimeofday(0x%llx,0x%llx) ]\n",
1571 (long long)arg0, (long long)arg1);
1572 result_low = gettimeofday(&tv, &tz);
1573 if (result_low) {
1574 error_flag = 1;
1575 error_code = errno;
1576 } else {
1577 if (arg0 != 0) {
1578 /* Store tv.tv_sec and tv.tv_usec
1579 as 'long' (32-bit) values: */
1580 store_32bit_word(cpu, arg0 + 0, tv.tv_sec);
1581 store_32bit_word(cpu, arg0 + 4, tv.tv_usec);
1582 }
1583 if (arg1 != 0) {
1584 /* Store tz.tz_minuteswest and
1585 tz.tz_dsttime as 'long' (32-bit) values: */
1586 store_32bit_word(cpu, arg1 + 0,
1587 tz.tz_minuteswest);
1588 store_32bit_word(cpu, arg1 + 4, tz.tz_dsttime);
1589 }
1590 }
1591 break;
1592
1593 default:
1594 fatal("[ UNIMPLEMENTED ultrix syscall %i ]\n", sysnr);
1595 error_flag = 1;
1596 error_code = 78; /* ENOSYS */
1597 }
1598
1599 /*
1600 * Ultrix/mips return values:
1601 *
1602 * TODO
1603 *
1604 * a3 is 0 if the syscall was ok, otherwise 1.
1605 * v0 (and sometimes v1) contain the result value.
1606 */
1607 cpu->cd.mips.gpr[MIPS_GPR_A3] = error_flag;
1608 if (error_flag)
1609 cpu->cd.mips.gpr[MIPS_GPR_V0] = error_code;
1610 else
1611 cpu->cd.mips.gpr[MIPS_GPR_V0] = result_low;
1612
1613 if (result_high_set)
1614 cpu->cd.mips.gpr[MIPS_GPR_V1] = result_high;
1615
1616 /* TODO */
1617 }
1618
1619
1620 /*
1621 * useremul_name_to_useremul():
1622 *
1623 * Example:
1624 * Input: name = "netbsd/pmax"
1625 * Output: sets *arch = ARCH_MIPS, *machine_name = "NetBSD/pmax",
1626 * and *cpu_name = "R3000".
1627 */
1628 void useremul_name_to_useremul(struct cpu *cpu, char *name, int *arch,
1629 char **machine_name, char **cpu_name)
1630 {
1631 struct syscall_emul *sep;
1632
1633 sep = first_syscall_emul;
1634
1635 while (sep != NULL) {
1636 if (strcasecmp(name, sep->name) == 0) {
1637 if (cpu_family_ptr_by_number(sep->arch) == NULL) {
1638 printf("\nSupport for the CPU family needed"
1639 " for '%s' userland emulation was not"
1640 " enabled at configuration time.\n",
1641 sep->name);
1642 exit(1);
1643 }
1644
1645 if (cpu != NULL)
1646 cpu->useremul_syscall = sep->f;
1647
1648 if (arch != NULL)
1649 *arch = sep->arch;
1650
1651 if (machine_name != NULL) {
1652 *machine_name = strdup(sep->name);
1653 if (*machine_name == NULL) {
1654 printf("out of memory\n");
1655 exit(1);
1656 }
1657 }
1658
1659 if (cpu_name != NULL) {
1660 *cpu_name = strdup(sep->cpu_name);
1661 if (*cpu_name == NULL) {
1662 printf("out of memory\n");
1663 exit(1);
1664 }
1665 }
1666 return;
1667 }
1668
1669 sep = sep->next;
1670 }
1671
1672 fatal("Unknown userland emulation '%s'\n", name);
1673 exit(1);
1674 }
1675
1676
1677 /*
1678 * add_useremul():
1679 *
1680 * For internal use, from useremul_init() only. Adds an emulation mode.
1681 */
1682 static void add_useremul(char *name, int arch, char *cpu_name,
1683 void (*f)(struct cpu *, uint32_t),
1684 void (*setup)(struct cpu *, int, char **))
1685 {
1686 struct syscall_emul *sep;
1687
1688 sep = malloc(sizeof(struct syscall_emul));
1689 if (sep == NULL) {
1690 printf("add_useremul(): out of memory\n");
1691 exit(1);
1692 }
1693 memset(sep, 0, sizeof(sep));
1694
1695 sep->name = name;
1696 sep->arch = arch;
1697 sep->cpu_name = cpu_name;
1698 sep->f = f;
1699 sep->setup = setup;
1700
1701 sep->next = first_syscall_emul;
1702 first_syscall_emul = sep;
1703 }
1704
1705
1706 /*
1707 * useremul_list_emuls():
1708 *
1709 * List all available userland emulation modes. (Actually, only those which
1710 * have CPU support enabled.)
1711 */
1712 void useremul_list_emuls(void)
1713 {
1714 struct syscall_emul *sep;
1715 int iadd = 8;
1716
1717 sep = first_syscall_emul;
1718
1719 if (sep == NULL)
1720 return;
1721
1722 debug("The following userland-only (syscall) emulation modes are"
1723 " available:\n\n");
1724 debug_indentation(iadd);
1725
1726 while (sep != NULL) {
1727 if (cpu_family_ptr_by_number(sep->arch) != NULL) {
1728 debug("%s (default CPU \"%s\")\n",
1729 sep->name, sep->cpu_name);
1730 }
1731
1732 sep = sep->next;
1733 }
1734
1735 debug_indentation(-iadd);
1736 debug("\n(Most of these modes are bogus.)\n\n");
1737 }
1738
1739
1740 /*
1741 * useremul_init():
1742 *
1743 * This function should be called before any other useremul_*() function
1744 * is used.
1745 */
1746 void useremul_init(void)
1747 {
1748 /* Note: These are in reverse alphabetic order: */
1749
1750 add_useremul("Ultrix", ARCH_MIPS, "R3000",
1751 useremul__ultrix, useremul__ultrix_setup);
1752
1753 add_useremul("NetBSD/powerpc", ARCH_PPC, "PPC750",
1754 useremul__netbsd, useremul__netbsd_setup);
1755
1756 add_useremul("NetBSD/pmax", ARCH_MIPS, "R3000",
1757 useremul__netbsd, useremul__netbsd_setup);
1758
1759 add_useremul("NetBSD/arm", ARCH_ARM, "SA1110",
1760 useremul__netbsd, useremul__netbsd_setup);
1761
1762 add_useremul("NetBSD/amd64", ARCH_X86, "AMD64",
1763 useremul__netbsd, useremul__netbsd_setup);
1764
1765 add_useremul("NetBSD/alpha", ARCH_ALPHA, "Alpha",
1766 useremul__netbsd, useremul__netbsd_setup);
1767
1768 add_useremul("Linux/PPC64", ARCH_PPC, "PPC970",
1769 useremul__linux, useremul__linux_setup);
1770
1771 add_useremul("FreeBSD/Alpha", ARCH_ALPHA, "Alpha",
1772 useremul__freebsd, useremul__freebsd_setup);
1773 }
1774

  ViewVC Help
Powered by ViewVC 1.1.26