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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 18 - (show annotations)
Mon Oct 8 16:19:11 2007 UTC (16 years, 6 months ago) by dpavlin
Original Path: trunk/src/useremul.c
File MIME type: text/plain
File size: 43571 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1004 2005/10/27 14:01:10 debug Exp $
20051011        Passing -A as the default boot arg for CATS (works fine with
                OpenBSD/cats).
20051012	Fixing the VGA cursor offset bug, and speeding up framebuffer
		redraws if character cells contain the same thing as during
		the last redraw.
20051013	Adding a slow strd ARM instruction hack.
20051017	Minor updates: Adding a dummy i80321 Verde controller (for
		XScale emulation), fixing the disassembly of the ARM "ldrd"
		instruction, adding "support" for less-than-4KB pages for ARM
		(by not adding them to translation tables).
20051020	Continuing on some HPCarm stuff. A NetBSD/hpcarm kernel prints
		some boot messages on an emulated Jornada 720.
		Making dev_ram work better with dyntrans (speeds up some things
		quite a bit).
20051021	Automatically generating some of the most common ARM load/store
		multiple instructions.
20051022	Better statistics gathering for the ARM load/store multiple.
		Various other dyntrans and device updates.
20051023	Various minor updates.
20051024	Continuing; minor device and dyntrans fine-tuning. Adding the
		first "reasonable" instruction combination hacks for ARM (the
		cores of NetBSD/cats' memset and memcpy).
20051025	Fixing a dyntrans-related bug in dev_vga. Also changing the
		dyntrans low/high access notification to only be updated on
		writes, not reads. Hopefully it will be enough. (dev_vga in
		charcell mode now seems to work correctly with both reads and
		writes.)
		Experimenting with gathering dyntrans statistics (which parts
		of emulated RAM that are actually executed), and adding
		instruction combination hacks for cache cleaning and a part of
		NetBSD's scanc() function.
20051026	Adding a bitmap for ARM emulation which indicates if a page is
		(specifically) user accessible; loads and stores with the t-
		flag set can now use the translation arrays, which results in
		a measurable speedup.
20051027	Dyntrans updates; adding an extra bitmap array for 32-bit
		emulation modes, speeding up the check whether a physical page
		has any code translations or not (O(n) -> O(1)). Doing a
		similar reduction of O(n) to O(1) by avoiding the scan through
		the translation entries on a translation update (32-bit mode
		only).
		Various other minor hacks.
20051029	Quick release, without any testing at all.

==============  RELEASE 0.3.6.2  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26