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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26