/[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 4 - (show annotations)
Mon Oct 8 16:18:00 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 37106 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.707 2005/04/27 16:37:33 debug Exp $
20050408	Some minor updates to the wdc. Linux now doesn't complain
		anymore if a disk is non-present.
20050409	Various minor fixes (a bintrans bug, and some other things).
		The wdc seems to work with Playstation2 emulation, but there
		is a _long_ annoying delay when disks are detected.
		Fixing a really important bintrans bug (when devices and RAM
		are mixed within 4KB pages), which was triggered with
		NetBSD/playstation2 kernels.
20050410	Adding a dummy dev_ps2_ether (just so that NetBSD doesn't
		complain as much during bootup).
		Symbols starting with '$' are now ignored.
		Renaming dev_ps2_ohci.c to dev_ohci.c, etc.
20050411	Moving the bintrans-cache-isolation check from cpu_mips.c to
		cpu_mips_coproc.c. (I thought this would give a speedup, but
		it's not noticable.)
		Better playstation2 sbus interrupt code.
		Skip ahead many ticks if the count register is read manually.
		(This increases the speed of delay-loops that simply read
		the count register.)
20050412	Updates to the playstation2 timer/interrupt code.
		Some other minor updates.
20050413	NetBSD/cobalt runs from a disk image :-) including userland;
		updating the documentation on how to install NetBSD/cobalt
		using NetBSD/pmax (!).
		Some minor bintrans updates (no real speed improvement) and
		other minor updates (playstation2 now uses the -o options).
20050414	Adding a dummy x86 (and AMD64) mode.
20050415	Adding some (32-bit and 16-bit) x86 instructions.
		Adding some initial support for non-SCSI, non-IDE floppy
		images. (The x86 mode can boot from these, more or less.)
		Moving the devices/ and include/ directories to src/devices/
		and src/include/, respectively.
20050416	Continuing on the x86 stuff. (Adding pc_bios.c and some simple
		support for software interrupts in 16-bit mode.)
20050417	Ripping out most of the x86 instruction decoding stuff, trying
		to rewrite it in a cleaner way.
		Disabling some of the least working CPU families in the
		configure script (sparc, x86, alpha, hppa), so that they are
		not enabled by default.
20050418	Trying to fix the bug which caused problems when turning on
		and off bintrans interactively, by flushing the bintrans cache
		whenever bintrans is manually (re)enabled.
20050419	Adding the 'lswi' ppc instruction.
		Minor updates to the x86 instruction decoding.
20050420	Renaming x86 register name indices from R_xx to X86_R_xx (this
		makes building on Tru64 nicer).
20050422	Adding a check for duplicate MIPS TLB entries on tlbwr/tlbwi.
20050427	Adding screenshots to guestoses.html.
		Some minor fixes and testing for the next release.

==============  RELEASE 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