/[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 22 - (show annotations)
Mon Oct 8 16:19:37 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 43685 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1121 2006/02/18 21:03:08 debug Exp $
20051126	Cobalt and PReP now work with the 21143 NIC.
		Continuing on Alpha dyntrans things.
		Fixing some more left-shift-by-24 to unsigned.
20051127	Working on OpenFirmware emulation; major cleanup/redesign.
		Progress on MacPPC emulation: NetBSD detects two CPUs (when
		running with -n 2), framebuffer output (for text) works.
		Adding quick-hack Bandit PCI controller and "gc" interrupt
		controller for MacPPC.
20051128	Changing from a Bandit to a Uni-North controller for macppc.
		Continuing on OpenFirmware and MacPPC emulation in general
		(obio controller, and wdc attached to the obio seems to work).
20051129	More work on MacPPC emulation (adding a dummy ADB controller).
		Continuing the PCI bus cleanup (endianness and tag composition)
		and rewriting all PCI controllers' access functions.
20051130	Various minor PPC dyntrans optimizations.
		Manually inlining some parts of the framebuffer redraw routine.
		Slowly beginning the conversion of the old MIPS emulation into
		dyntrans (but this will take quite some time to get right).
		Generalizing quick_pc_to_pointers.
20051201	Documentation update (David Muse has made available a kernel
		which simplifies Debian/DECstation installation).
		Continuing on the ADB bus controller.
20051202	Beginning a rewrite of the Zilog serial controller (dev_zs).
20051203	Continuing on the zs rewrite (now called dev_z8530); conversion
		to devinit style.
		Reworking some of the input-only vs output-only vs input-output
		details of src/console.c, better warning messages, and adding
		a debug dump.
		Removing the concept of "device state"; it wasn't really used.
		Changing some debug output (-vv should now be used to show all
		details about devices and busses; not shown during normal
		startup anymore).
		Beginning on some SPARC instruction disassembly support.
20051204	Minor PPC updates (WALNUT skeleton stuff).
		Continuing on the MIPS dyntrans rewrite.
		More progress on the ADB controller (a keyboard is "detected"
		by NetBSD and OpenBSD).
		Downgrading OpenBSD/arc as a guest OS from "working" to
		"almost working" in the documentation.
		Progress on Algor emulation ("v3" PCI controller).
20051205	Minor updates.
20051207	Sorting devices according to address; this reduces complexity
		of device lookups from O(n) to O(log n) in memory_rw (but no
		real performance increase (yet) in experiments).
20051210	Beginning the work on native dyntrans backends (by making a
		simple skeleton; so far only for Alpha hosts).
20051211	Some very minor SPARC updates.
20051215	Fixing a bug in the MIPS mul (note: not mult) instruction,
		so it also works with non-64-bit emulation. (Thanks to Alec
		Voropay for noticing the problem.)
20051216	More work on the fake/empty/simple/skeleton/whatever backend;
		performance doesn't increase, so this isn't really worth it,
		but it was probably worth it to prepare for a real backend
		later.
20051219	More instr call statistics gathering and analysis stuff.
20051220	Another fix for MIPS 'mul'. Also converting mul and {d,}cl{o,z}
		to dyntrans.
		memory_ppc.c syntax error fix (noticed by Peter Valchev).
		Beginning to move out machines from src/machine.c into
		individual files in src/machines (in a way similar to the
		autodev system for devices).
20051222	Updating the documentation regarding NetBSD/pmax 3.0.
20051223	- " - NetBSD/cats 3.0.
20051225	- " - NetBSD/hpcmips 3.0.
20051226	Continuing on the machine registry redesign.
		Adding support for ARM rrx (33-bit rotate).
		Fixing some signed/unsigned issues (exposed by gcc -W).
20051227	Fixing the bug which prevented a NetBSD/prep 3.0 install kernel
		from starting (triggered when an mtmsr was the last instruction
		on a page). Unfortunately not enough to get the kernel to run
		as well as the 2.1 kernels did.
20051230	Some dyntrans refactoring.
20051231	Continuing on the machine registry redesign.
20060101-10	Continuing... moving more machines. Moving MD interrupt stuff
		from machine.c into a new src/machines/interrupts.c.
20060114	Adding various mvmeppc machine skeletons.
20060115	Continuing on mvme* stuff. NetBSD/mvmeppc prints boot messages
		(for MVME1600) and reaches the root device prompt, but no
		specific hardware devices are emulated yet.
20060116	Minor updates to the mvme1600 emulation mode; the Eagle PCI bus
		seems to work without much modification, and a 21143 can be
		detected, interrupts might work (but untested so far).
		Adding a fake MK48Txx (mkclock) device, for NetBSD/mvmeppc.
20060121	Adding an aux control register for ARM. (A BIG thank you to
		Olivier Houchard for tracking down this bug.)
20060122	Adding more ARM instructions (smulXY), and dev_iq80321_7seg.
20060124	Adding disassembly of more ARM instructions (mia*, mra/mar),
		and some semi-bogus XScale and i80321 registers.
20060201-02	Various minor updates. Moving the last machines out of
		machine.c.
20060204	Adding a -c command line option, for running debugger commands
		before the simulation starts, but after all files have been
		loaded.
		Minor iq80321-related updates.
20060209	Minor hacks (DEVINIT macro, etc).
		Preparing for the generalization of the 64-bit dyntrans address
		translation subsystem.
20060216	Adding ARM ldrd (double-register load).
20060217	Continuing on various ARM-related stuff.
20060218	More progress on the ATA/wdc emulation for NetBSD/iq80321.
		NetBSD/evbarm can now be installed :-)  Updating the docs, etc.
		Continuing on Algor emulation.

==============  RELEASE 0.3.8  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26