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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 36 - (show annotations)
Mon Oct 8 16:21:34 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 43974 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1497 2007/03/18 03:41:36 debug Exp $
20070224	Minor update to the initialization of the ns16550 in
		machine_walnut.c, to allow that machine type to boot with the
		new interrupt system (although it is still a dummy machine).
		Adding a wdc at 0x14000000 to machine_landisk.c, and fixing
		the SCIF serial interrupts of the SH4 cpu enough to get
		NetBSD/landisk booting from a disk image :-)  Adding a
		preliminary install instruction skeleton to guestoses.html.
20070306	Adding SH-IPL+G PROM emulation, and also passing the "end"
		symbol in r5 on bootup, for Landisk emulation. This is enough
		to get OpenBSD/landisk to install :)  Adding a preliminary
		install instruction skeleton to the documentation. SuperH
		emulation is still shaky, though :-/
20070307	Fixed a strangeness in memory_sh.c (read/write was never
		returned for any page). (Unknown whether this fixes any actual
		problems, though.)
20070308	dev_ram.c fix: invalidate code translations on writes to
		RAM, emulated as separate devices. Linux/dreamcast gets
		further in the boot process than before, but still bugs out
		in userland.
		Fixing bugs in the "stc.l gbr,@-rN" and "ldc.l @rN+,gbr" SuperH 
		instructions (they should NOT check the MD bit), allowing the
		Linux/dreamcast Live CD to reach userland correctly :-)
20070310	Changing the cpu name "Alpha" in src/useremul.c to "21364" to
		unbreak userland syscall emulation of FreeBSD/Alpha binaries.
20070314	Applying a patch from Michael Yaroslavtsev which fixes the
		previous Linux lib64 patch to the configure script.
20070315	Adding a (dummy) sun4v machine type, and SPARC T1 cpu type.
20070316	Creating a new directory, src/disk, and moving diskimage.c
		to it. Separating out bootblock loading stuff from emul.c into
		new files in src/disk.
		Adding some more SPARC registers.
20070318	Preparing/testing for a minirelease, 0.4.4.1.

==============  RELEASE 0.4.4.1  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26