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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

  ViewVC Help
Powered by ViewVC 1.1.26