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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26