/[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 14 - (show annotations)
Mon Oct 8 16:18:51 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 43578 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.982 2005/10/07 22:45:32 debug Exp $
20050816	Some success in decoding the way the SGI O2 PROM draws graphics
		during bootup; lines/rectangles and bitmaps work, enough to
		show the bootlogo etc. :-)
		Adding more PPC instructions, and (dummy) BAT registers.
20050817	Updating the pckbc to support scancode type 3 keyboards
		(required in order to interact with the SGI O2 PROM).
		Adding more PPC instructions.
20050818	Adding more ARM instructions; general register forms.
		Importing armreg.h from NetBSD (ARM cpu ids). Adding a (dummy)
		CATS machine mode (using SA110 as the default CPU).
		Continuing on general dyntrans related stuff.
20050819	Register forms for ARM load/stores. Gaah! The Compaq C Compiler
		bug is triggered for ARM loads as well, not just PPC :-(
		Adding full support for ARM PC-relative load/stores, and load/
		stores where the PC register is the destination register.
		Adding support for ARM a.out binaries.
20050820	Continuing to add more ARM instructions, and correcting some
		bugs. Continuing on CATS emulation.
		More work on the PPC stuff.
20050821	Minor PPC and ARM updates. Adding more machine types.
20050822	All ARM "data processing instructions" are now generated
		automatically.
20050824	Beginning the work on the ARM system control coprocessor.
		Adding support for ARM halfword load/stores, and signed loads.
20050825	Fixing an important bug related to the ARM condition codes.
		OpenBSD/zaurus and NetBSD/netwinder now print some boot
		messages. :)
		Adding a dummy SH (Hitachi SuperH) cpu family.
		Beginning to add some ARM virtual address translation.
		MIPS bugfixes: unaligned PC now cause an ADEL exception (at
		least for non-bintrans execution), and ADEL/ADES (not
		TLBL/TLBS) are used if userland tries to access kernel space.
		(Thanks to Joshua Wise for making me aware of these bugs.)
20050827	More work on the ARM emulation, and various other updates.
20050828	More ARM updates.
		Finally taking the time to work on translation invalidation
		(i.e. invalidating translated code mappings when memory is
		written to). Hopefully this doesn't break anything.
20050829	Moving CPU related files from src/ to a new subdir, src/cpus/.
		Moving PROM emulation stuff from src/ to src/promemul/.
		Better debug instruction trace for ARM loads and stores.
20050830	Various ARM updates (correcting CMP flag calculation, etc).
20050831	PPC instruction updates. (Flag fixes, etc.)
20050901	Various minor PPC and ARM instruction emulation updates.
		Minor OpenFirmware emulation updates.
20050903	Adding support for adding arbitrary ARM coprocessors (with
		the i80321 I/O coprocessor as a first test).
		Various other ARM and PPC updates.
20050904	Adding some SHcompact disassembly routines.
20050907	(Re)adding a dummy HPPA CPU module, and a dummy i960 module.
20050908	Began hacking on some Apple Partition Table support.
20050909	Adding support for loading Mach-O (Darwin PPC) binaries.
20050910	Fixing an ARM bug (Carry flag was incorrectly updated for some
		data processing instructions); OpenBSD/cats and NetBSD/
		netwinder get quite a bit further now.
		Applying a patch to dev_wdc, and a one-liner to dev_pcic, to
		make them work better when emulating new versions of OpenBSD.
		(Thanks to Alexander Yurchenko for the patches.)
		Also doing some other minor updates to dev_wdc. (Some cleanup,
		and finally converting to devinit, etc.)
20050912	IRIX doesn't have u_int64_t by default (noticed by Andreas
		<avr@gnulinux.nl>); configure updated to reflect this.
		Working on ARM register bank switching, CPSR vs SPSR issues,
		and beginning the work on interrupt/exception support.
20050913	Various minor ARM updates (speeding up load/store multiple,
		and fixing a ROR bug in R(); NetBSD/cats now boots as far as
		OpenBSD/cats).
20050917	Adding a dummy Atmel AVR (8-bit) cpu family skeleton.
20050918	Various minor updates.
20050919	Symbols are now loaded from Mach-O executables.
		Continuing the work on adding ARM exception support.
20050920	More work on ARM stuff: OpenBSD/cats and NetBSD/cats reach
		userland! :-)
20050921	Some more progress on ARM interrupt specifics.
20050923	Fixing linesize for VR4121 (patch by Yurchenko). Also fixing
		linesizes/cachesizes for some other VR4xxx.
		Adding a dummy Acer Labs M1543 PCI-ISA bridge (for CATS) and a
		dummy Symphony Labs 83C553 bridge (for Netwinder), usable by 
		dev_footbridge.
20050924	Some PPC progress.
20050925	More PPC progress.
20050926	PPC progress (fixing some bugs etc); Darwin's kernel gets
		slightly further than before.
20050928	Various updates: footbridge/ISA/pciide stuff, and finally
		fixing the VGA text scroll-by-changing-the-base-offset bug.
20050930	Adding a dummy S3 ViRGE pci card for CATS emulation, which
		both NetBSD and OpenBSD detects as VGA.
		Continuing on Footbridge (timers, ISA interrupt stuff).
20051001	Continuing... there are still bugs, probably interrupt-
		related.
20051002	More work on the Footbridge (interrupt stuff).
20051003	Various minor updates. (Trying to find the bug(s).)
20051004	Continuing on the ARM stuff.
20051005	More ARM-related fixes.
20051007	FINALLY! Found and fixed 2 ARM bugs: 1 memory related, and the
		other was because of an error in the ARM manual (load multiple
		with the S-bit set should _NOT_ load usermode registers, as the
		manual says, but it should load saved registers, which may or
		may not happen to be usermode registers).
		NetBSD/cats and OpenBSD/cats seem to install fine now :-)
		except for a minor bug at the end of the OpenBSD/cats install.
		Updating the documentation, preparing for the next release.
20051008	Continuing with release testing and cleanup.

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.64 2005/08/27 17:29:06 debug Exp $
29 *
30 * Userland (syscall) emulation.
31 *
32 * TODO:
33 *
34 * environment passing for most emulation modes
35 *
36 * implement more syscalls
37 *
38 * 32-bit vs 64-bit problems? MIPS n32, o32, n64?
39 *
40 * Dynamic ELFs?
41 *
42 * Try to prefix "/emul/mips/" or similar to all filenames,
43 * and only if that fails, try the given filename
44 *
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 ssize_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 117:res = useremul_getrusage(cpu, &err, arg0, arg1);
703 break;
704
705 case 189:res = useremul_fstat(cpu, &err, arg0, arg1);
706 break;
707
708 case 197:res = useremul_mmap(cpu, &err, arg0, arg1, arg2, arg3,
709 arg4, arg5);
710 break;
711
712 default:fatal("useremul__freebsd(): syscall %i not yet "
713 "implemented\n", nr);
714 cpu->running = 0;
715 }
716
717 if (err) {
718 cpu->cd.alpha.r[ALPHA_A3] = 1;
719 cpu->cd.alpha.r[ALPHA_V0] = err;
720 } else {
721 cpu->cd.alpha.r[ALPHA_A3] = 0;
722 cpu->cd.alpha.r[ALPHA_V0] = res;
723 }
724 }
725
726
727 /*
728 * useremul__linux():
729 *
730 * Linux syscall emulation.
731 *
732 * TODO: How to make this work nicely with non-PPC archs.
733 */
734 static void useremul__linux(struct cpu *cpu, uint32_t code)
735 {
736 int nr;
737 int64_t res = 0, err = 0;
738 uint64_t arg0, arg1, arg2, arg3;
739
740 if (code != 0) {
741 fatal("useremul__linux(): code %i: TODO\n", (int)code);
742 exit(1);
743 }
744
745 nr = cpu->cd.ppc.gpr[0];
746 arg0 = cpu->cd.ppc.gpr[3];
747 arg1 = cpu->cd.ppc.gpr[4];
748 arg2 = cpu->cd.ppc.gpr[5];
749 arg3 = cpu->cd.ppc.gpr[6];
750
751 switch (nr) {
752
753 case LINUX_PPC_SYS_exit:
754 res = useremul_exit(cpu, arg0);
755 break;
756
757 case LINUX_PPC_SYS_write:
758 res = useremul_write(cpu, &err, arg0, arg1, arg2);
759 break;
760
761 default:
762 fatal("useremul__linux(): syscall %i not yet implemented\n",
763 nr);
764 cpu->running = 0;
765 }
766
767 /* return res: TODO */
768 }
769
770
771 /*
772 * useremul__netbsd():
773 *
774 * NetBSD syscall emulation.
775 */
776 static void useremul__netbsd(struct cpu *cpu, uint32_t code)
777 {
778 int error_flag = 0, result_high_set = 0;
779 uint64_t arg0=0,arg1=0,arg2=0,arg3=0,stack0=0,stack1=0,stack2=0;
780 int sysnr = 0;
781 int64_t error_code = 0;
782 uint64_t result_low = 0;
783 uint64_t result_high = 0;
784 struct timeval tv;
785 struct timezone tz;
786 int descr;
787 uint64_t length, mipsbuf, flags;
788 unsigned char *charbuf;
789 uint32_t sysctl_name, sysctl_namelen, sysctl_oldp,
790 sysctl_oldlenp, sysctl_newp, sysctl_newlen;
791 uint32_t name0, name1, name2, name3;
792
793 switch (cpu->machine->arch) {
794 case ARCH_MIPS:
795 sysnr = cpu->cd.mips.gpr[MIPS_GPR_V0];
796 if (sysnr == NETBSD_SYS___syscall) {
797 sysnr = cpu->cd.mips.gpr[MIPS_GPR_A0] +
798 (cpu->cd.mips.gpr[MIPS_GPR_A1] << 32);
799 arg0 = cpu->cd.mips.gpr[MIPS_GPR_A2];
800 arg1 = cpu->cd.mips.gpr[MIPS_GPR_A3];
801 /* TODO: stack arguments? Are these correct? */
802 arg2 = load_32bit_word(cpu,
803 cpu->cd.mips.gpr[MIPS_GPR_SP] + 8);
804 arg3 = load_32bit_word(cpu,
805 cpu->cd.mips.gpr[MIPS_GPR_SP] + 16);
806 stack0 = load_32bit_word(cpu,
807 cpu->cd.mips.gpr[MIPS_GPR_SP] + 24);
808 stack1 = load_32bit_word(cpu,
809 cpu->cd.mips.gpr[MIPS_GPR_SP] + 32);
810 stack2 = load_32bit_word(cpu,
811 cpu->cd.mips.gpr[MIPS_GPR_SP] + 40);
812 } else {
813 arg0 = cpu->cd.mips.gpr[MIPS_GPR_A0];
814 arg1 = cpu->cd.mips.gpr[MIPS_GPR_A1];
815 arg2 = cpu->cd.mips.gpr[MIPS_GPR_A2];
816 arg3 = cpu->cd.mips.gpr[MIPS_GPR_A3];
817 /* TODO: stack arguments? Are these correct? */
818 stack0 = load_32bit_word(cpu,
819 cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
820 stack1 = load_32bit_word(cpu,
821 cpu->cd.mips.gpr[MIPS_GPR_SP] + 8);
822 stack2 = load_32bit_word(cpu,
823 cpu->cd.mips.gpr[MIPS_GPR_SP] + 12);
824 }
825 break;
826
827 case ARCH_PPC:
828 sysnr = cpu->cd.ppc.gpr[0];
829 arg0 = cpu->cd.ppc.gpr[3];
830 arg1 = cpu->cd.ppc.gpr[4];
831 arg2 = cpu->cd.ppc.gpr[5];
832 arg3 = cpu->cd.ppc.gpr[6];
833 /* TODO: More arguments? Stack arguments? */
834 break;
835
836 case ARCH_ARM:
837 sysnr = code & 0xfffff;
838 arg0 = cpu->cd.arm.r[0];
839 arg1 = cpu->cd.arm.r[1];
840 arg2 = cpu->cd.arm.r[2];
841 arg3 = cpu->cd.arm.r[3];
842 /* TODO: More arguments? Stack arguments? */
843 break;
844
845 default:fatal("netbsd syscall for this arch: TODO\n");
846 exit(1);
847 }
848
849 /*
850 * NOTE: The following code should not be CPU arch dependant!
851 * (TODO)
852 */
853
854 switch (sysnr) {
855
856 case NETBSD_SYS_exit:
857 debug("[ exit(%i) ]\n", (int)arg0);
858 cpu->running = 0;
859 cpu->machine->exit_without_entering_debugger = 1;
860 break;
861
862 case NETBSD_SYS_read:
863 debug("[ read(%i,0x%llx,%lli) ]\n",
864 (int)arg0, (long long)arg1, (long long)arg2);
865
866 if (arg2 != 0) {
867 charbuf = malloc(arg2);
868 if (charbuf == NULL) {
869 fprintf(stderr, "out of memory in "
870 "useremul__netbsd()\n");
871 exit(1);
872 }
873 result_low = read(arg0, charbuf, arg2);
874 if ((int64_t)result_low < 0) {
875 error_code = errno;
876 error_flag = 1;
877 }
878
879 /* TODO: address validity check */
880 cpu->memory_rw(cpu, cpu->mem, arg1, charbuf,
881 arg2, MEM_WRITE, CACHE_DATA);
882 free(charbuf);
883 }
884 break;
885
886 case NETBSD_SYS_write:
887 descr = arg0;
888 mipsbuf = arg1;
889 length = arg2;
890 debug("[ write(%i,0x%llx,%lli) ]\n",
891 (int)descr, (long long)mipsbuf, (long long)length);
892 if (length != 0) {
893 charbuf = malloc(length);
894 if (charbuf == NULL) {
895 fprintf(stderr, "out of memory in "
896 "useremul__netbsd()\n");
897 exit(1);
898 }
899 /* TODO: address validity check */
900 cpu->memory_rw(cpu, cpu->mem, mipsbuf, charbuf,
901 length, MEM_READ, CACHE_DATA);
902 result_low = write(descr, charbuf, length);
903 if ((int64_t)result_low < 0) {
904 error_code = errno;
905 error_flag = 1;
906 }
907 free(charbuf);
908 }
909 break;
910
911 case NETBSD_SYS_open:
912 charbuf = get_userland_string(cpu, arg0);
913 debug("[ open(\"%s\", 0x%llx, 0x%llx) ]\n",
914 charbuf, (long long)arg1, (long long)arg2);
915 result_low = open((char *)charbuf, arg1, arg2);
916 if ((int64_t)result_low < 0) {
917 error_flag = 1;
918 error_code = errno;
919 }
920 free(charbuf);
921 break;
922
923 case NETBSD_SYS_close:
924 descr = arg0;
925 debug("[ close(%i) ]\n", (int)descr);
926 error_code = close(descr);
927 if (error_code != 0)
928 error_flag = 1;
929 break;
930
931 case NETBSD_SYS_access:
932 charbuf = get_userland_string(cpu, arg0);
933 debug("[ access(\"%s\", 0x%llx) ]\n",
934 charbuf, (long long) arg1);
935 result_low = access((char *)charbuf, arg1);
936 if (result_low != 0) {
937 error_flag = 1;
938 error_code = errno;
939 }
940 free(charbuf);
941 break;
942
943 case NETBSD_SYS_getuid:
944 result_low = useremul_getuid(cpu);
945 break;
946
947 case NETBSD_SYS_geteuid:
948 debug("[ geteuid() ]\n");
949 result_low = geteuid();
950 break;
951
952 case NETBSD_SYS_getgid:
953 debug("[ getgid() ]\n");
954 result_low = getgid();
955 break;
956
957 case NETBSD_SYS_getegid:
958 debug("[ getegid() ]\n");
959 result_low = getegid();
960 break;
961
962 case NETBSD_SYS_getfsstat:
963 mipsbuf = arg0;
964 length = arg1;
965 flags = arg2;
966 debug("[ getfsstat(0x%llx,%lli,0x%llx) ]\n",
967 (long long)mipsbuf, (long long)length,
968 (long long)flags);
969
970 result_low = 0; /* nr of mounted filesystems,
971 for now (TODO) */
972
973 /* Fill in the struct statfs buffer at arg0...
974 copy data from the host's getfsstat(). TODO */
975 #if 1
976 result_low = 1;
977 store_32bit_word(cpu, mipsbuf + 0, 0); /* f_spare2 */
978 store_32bit_word(cpu, mipsbuf + 4, 1024); /* f_bsize */
979 store_32bit_word(cpu, mipsbuf + 8, 65536); /* f_iosize */
980 store_32bit_word(cpu, mipsbuf + 12, 100); /* f_blocks */
981 store_32bit_word(cpu, mipsbuf + 16, 50); /* f_bfree */
982 store_32bit_word(cpu, mipsbuf + 20, 10); /* f_bavail */
983 store_32bit_word(cpu, mipsbuf + 24, 50); /* f_files */
984 store_32bit_word(cpu, mipsbuf + 28, 25); /* f_ffree */
985 store_32bit_word(cpu, mipsbuf + 28, 0x1234); /* f_fsid */
986 store_32bit_word(cpu, mipsbuf + 32, 0); /* f_owner */
987 store_32bit_word(cpu, mipsbuf + 36, 0); /* f_type */
988 store_32bit_word(cpu, mipsbuf + 40, 0); /* f_flags */
989 store_32bit_word(cpu, mipsbuf + 44, 0); /* f_fspare[0] */
990 store_32bit_word(cpu, mipsbuf + 48, 0); /* f_fspare[1] */
991 store_string(cpu, mipsbuf + 52, "ffs"); /* f_typename */
992 #define MFSNAMELEN 16
993 #define MNAMELEN 90
994 store_string(cpu, mipsbuf + 52 + MFSNAMELEN, "/");
995 /* f_mntonname */
996 store_string(cpu, mipsbuf + 52 + MFSNAMELEN + MNAMELEN, "ffs");
997 /* f_mntfromname */
998 #endif
999 break;
1000
1001 case NETBSD_SYS_break:
1002 useremul_break(cpu, arg0);
1003 break;
1004
1005 case NETBSD_SYS_readlink:
1006 result_low = useremul_readlink(cpu, &error_code,
1007 arg0, arg1, arg2);
1008 break;
1009
1010 case NETBSD_SYS_sync:
1011 useremul_sync(cpu);
1012 break;
1013
1014 case NETBSD_SYS_gettimeofday:
1015 debug("[ gettimeofday(0x%llx,0x%llx) ]\n",
1016 (long long)arg0, (long long)arg1);
1017 result_low = gettimeofday(&tv, &tz);
1018 if (result_low) {
1019 error_flag = 1;
1020 error_code = errno;
1021 } else {
1022 if (arg0 != 0) {
1023 /* Store tv.tv_sec and tv.tv_usec as
1024 'long' (32-bit) values: */
1025 store_32bit_word(cpu, arg0 + 0,
1026 tv.tv_sec);
1027 store_32bit_word(cpu, arg0 + 4,
1028 tv.tv_usec);
1029 }
1030 if (arg1 != 0) {
1031 /* Store tz.tz_minuteswest and
1032 tz.tz_dsttime as 'long'
1033 (32-bit) values: */
1034 store_32bit_word(cpu, arg1 + 0,
1035 tz.tz_minuteswest);
1036 store_32bit_word(cpu, arg1 + 4,
1037 tz.tz_dsttime);
1038 }
1039 }
1040 break;
1041
1042 case NETBSD_SYS_mmap:
1043 debug("[ mmap(0x%x,%i,%i,%i,%i,0x%llx): TODO ]\n",
1044 arg0, arg1, arg2, arg3, stack0, (long long)stack1);
1045
1046 if ((int32_t)stack0 == -1) {
1047 /*
1048 * Anonymous allocation:
1049 *
1050 * TODO: Fix this!!!
1051 *
1052 * This quick hack simply allocates anonymous
1053 * mmap memory approximately below the stack.
1054 * This will probably not work with dynamically
1055 * loaded libraries and such.
1056 */
1057 static uint32_t mmap_anon_ptr = 0x70000000;
1058 mmap_anon_ptr -= arg1;
1059 /* round down to page boundary: */
1060 mmap_anon_ptr &= ~4095;
1061 debug("ANON: %i bytes at 0x%08x (TODO: not "
1062 "working yet?)\n", (int)arg1,
1063 mmap_anon_ptr);
1064 result_low = mmap_anon_ptr;
1065 } else {
1066 /* Return NULL for now */
1067 }
1068 break;
1069
1070 case NETBSD_SYS_dup:
1071 debug("[ dup(%i) ]\n", (int)arg0);
1072 result_low = dup(arg0);
1073 if ((int64_t)result_low < 0) {
1074 error_code = errno;
1075 error_flag = 1;
1076 }
1077 break;
1078
1079 case NETBSD_SYS_socket:
1080 debug("[ socket(%i,%i,%i) ]\n",
1081 (int)arg0, (int)arg1, (int)arg2);
1082 result_low = socket(arg0,arg1,arg2);
1083 if ((int64_t)result_low < 0) {
1084 error_code = errno;
1085 error_flag = 1;
1086 }
1087 break;
1088
1089 case NETBSD_SYS_issetugid:
1090 debug("[ issetugid() ]\n");
1091 /* TODO: actually call the real issetugid? */
1092 break;
1093
1094 case NETBSD_SYS_nanosleep:
1095 debug("[ nanosleep(0x%llx,0x%llx) ]\n",
1096 (long long)arg0, (long long)arg1);
1097
1098 if (arg0 != 0) {
1099 uint32_t sec = load_32bit_word(cpu, arg0 + 0);
1100 uint32_t nsec = load_32bit_word(cpu, arg0 + 4);
1101 struct timespec ts;
1102 ts.tv_sec = sec;
1103 ts.tv_nsec = nsec;
1104 result_low = nanosleep(&ts, NULL);
1105 if (result_low)
1106 fprintf(stderr, "netbsd emulation "
1107 "nanosleep() failed\n");
1108 /* TODO: arg1 */
1109 } else {
1110 error_flag = 1;
1111 error_code = 14; /* EFAULT */
1112 }
1113 break;
1114
1115 case NETBSD_SYS___fstat13:
1116 debug("[ __fstat13(%lli,0x%llx): TODO ]\n",
1117 (long long)arg0, (long long)arg1);
1118 error_flag = 1;
1119 error_code = 9; /* EBADF */
1120 break;
1121
1122 case NETBSD_SYS___getcwd:
1123 debug("[ __getcwd(0x%llx,%lli): TODO ]\n",
1124 (long long)arg0, (long long)arg1);
1125 if (arg1 != 0 && arg1 < 500000) {
1126 char *buf = malloc(arg1);
1127 unsigned int i;
1128
1129 getcwd(buf, arg1);
1130
1131 /* zero-terminate in host's space: */
1132 buf[arg1 - 1] = 0;
1133
1134 for (i = 0; i<arg1 && i < arg1; i++)
1135 cpu->memory_rw(cpu, cpu->mem, arg0 + i,
1136 (unsigned char *)&buf[i], 1,
1137 MEM_WRITE, CACHE_NONE);
1138
1139 /* zero-terminate in emulated space: */
1140 cpu->memory_rw(cpu, cpu->mem, arg0 + arg1-1,
1141 (unsigned char *)&buf[arg1 - 1],
1142 1, MEM_WRITE, CACHE_NONE);
1143
1144 free(buf);
1145 }
1146 result_low = arg0;
1147 break;
1148
1149 case NETBSD_SYS___sigaction14:
1150 debug("[ __sigaction14(%lli,0x%llx,0x%llx): TODO ]\n",
1151 (long long)arg0, (long long)arg1, (long long)arg2);
1152 error_flag = 1;
1153 error_code = 9; /* EBADF */
1154 break;
1155
1156 case NETBSD_SYS___sysctl:
1157 sysctl_name = arg0;
1158 sysctl_namelen = arg1;
1159 sysctl_oldp = arg2;
1160 sysctl_oldlenp = arg3;
1161 sysctl_newp = load_32bit_word(cpu,
1162 cpu->cd.mips.gpr[MIPS_GPR_SP]);
1163 /* TODO: +4 and +8 ?? */
1164 sysctl_newlen = load_32bit_word(cpu,
1165 cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
1166 debug("[ __sysctl(");
1167
1168 name0 = load_32bit_word(cpu, sysctl_name + 0);
1169 name1 = load_32bit_word(cpu, sysctl_name + 4);
1170 name2 = load_32bit_word(cpu, sysctl_name + 8);
1171 name3 = load_32bit_word(cpu, sysctl_name + 12);
1172 debug("name (@ 0x%08x) = %i, %i, %i, %i) ]\n",
1173 sysctl_name, name0, name1, name2, name3);
1174
1175 if (name0 == CTL_KERN && name1 == KERN_HOSTNAME) {
1176 char hname[256];
1177 hname[0] = '\0';
1178 gethostname(hname, sizeof(hname));
1179 hname[sizeof(hname)-1] = '\0';
1180 if (sysctl_oldp != 0)
1181 store_string(cpu, sysctl_oldp, hname);
1182 if (sysctl_oldlenp != 0)
1183 store_32bit_word(cpu, sysctl_oldlenp,
1184 strlen(hname));
1185 } else if (name0 == CTL_HW && name1 == HW_PAGESIZE) {
1186 if (sysctl_oldp != 0)
1187 store_32bit_word(cpu,
1188 sysctl_oldp, 4096);
1189 if (sysctl_oldlenp != 0)
1190 store_32bit_word(cpu,
1191 sysctl_oldlenp, sizeof(uint32_t));
1192 } else {
1193 error_flag = 1;
1194 error_code = 2; /* ENOENT */
1195 }
1196 break;
1197
1198 default:
1199 fatal("[ UNIMPLEMENTED netbsd syscall %i ]\n", sysnr);
1200 error_flag = 1;
1201 error_code = 78; /* ENOSYS */
1202 }
1203
1204
1205 switch (cpu->machine->arch) {
1206 case ARCH_ARM:
1207 /* NetBSD/arm return values: */
1208 cpu->cd.arm.r[0] = result_low;
1209 cpu->cd.arm.cpsr &= ~ARM_FLAG_C;
1210 if (error_flag) {
1211 cpu->cd.arm.cpsr |= ARM_FLAG_C;
1212 cpu->cd.arm.r[0] = error_code;
1213 }
1214 if (result_high_set)
1215 cpu->cd.arm.r[1] = result_high;
1216 break;
1217 case ARCH_MIPS:
1218 /*
1219 * NetBSD/mips return values:
1220 *
1221 * a3 is 0 if the syscall was ok, otherwise 1.
1222 * v0 (and sometimes v1) contain the result value.
1223 */
1224 cpu->cd.mips.gpr[MIPS_GPR_A3] = error_flag;
1225 if (error_flag)
1226 cpu->cd.mips.gpr[MIPS_GPR_V0] = error_code;
1227 else
1228 cpu->cd.mips.gpr[MIPS_GPR_V0] = result_low;
1229
1230 if (result_high_set)
1231 cpu->cd.mips.gpr[MIPS_GPR_V1] = result_high;
1232 break;
1233 case ARCH_PPC:
1234 /*
1235 * NetBSD/powerpc return values:
1236 *
1237 * TODO
1238 */
1239 cpu->cd.ppc.gpr[3] = result_low;
1240
1241 if (result_high_set)
1242 cpu->cd.ppc.gpr[4] = result_high;
1243 break;
1244 }
1245 }
1246
1247
1248 /*
1249 * useremul__ultrix():
1250 *
1251 * Ultrix syscall emulation.
1252 */
1253 static void useremul__ultrix(struct cpu *cpu, uint32_t code)
1254 {
1255 int error_flag = 0, result_high_set = 0;
1256 uint64_t arg0,arg1,arg2,arg3,stack0=0,stack1=0,stack2;
1257 int sysnr = 0;
1258 int64_t error_code = 0;
1259 uint64_t result_low = 0;
1260 uint64_t result_high = 0;
1261 struct timeval tv;
1262 struct timezone tz;
1263 int descr;
1264 uint64_t length, mipsbuf;
1265 unsigned char *charbuf;
1266
1267 /*
1268 * Ultrix/pmax gets the syscall number in register v0,
1269 * and syscall arguments in registers a0, a1, ...
1270 *
1271 * TODO: If there is a __syscall-like syscall (as in NetBSD)
1272 * then 64-bit args may be passed in two registers or something...
1273 * If so, then copy from the section above (NetBSD).
1274 */
1275 sysnr = cpu->cd.mips.gpr[MIPS_GPR_V0];
1276
1277 arg0 = cpu->cd.mips.gpr[MIPS_GPR_A0];
1278 arg1 = cpu->cd.mips.gpr[MIPS_GPR_A1];
1279 arg2 = cpu->cd.mips.gpr[MIPS_GPR_A2];
1280 arg3 = cpu->cd.mips.gpr[MIPS_GPR_A3];
1281 /* TODO: stack arguments? Are these correct? */
1282 stack0 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 0);
1283 stack1 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 4);
1284 stack2 = load_32bit_word(cpu, cpu->cd.mips.gpr[MIPS_GPR_SP] + 8);
1285
1286 switch (sysnr) {
1287
1288 case ULTRIX_SYS_exit:
1289 debug("[ exit(%i) ]\n", (int)arg0);
1290 cpu->running = 0;
1291 cpu->machine->exit_without_entering_debugger = 1;
1292 break;
1293
1294 case ULTRIX_SYS_read:
1295 debug("[ read(%i,0x%llx,%lli) ]\n",
1296 (int)arg0, (long long)arg1, (long long)arg2);
1297
1298 if (arg2 != 0) {
1299 charbuf = malloc(arg2);
1300 if (charbuf == NULL) {
1301 fprintf(stderr, "out of memory in "
1302 "useremul__ultrix()\n");
1303 exit(1);
1304 }
1305
1306 result_low = read(arg0, charbuf, arg2);
1307 if ((int64_t)result_low < 0) {
1308 error_code = errno;
1309 error_flag = 1;
1310 }
1311
1312 /* TODO: address validity check */
1313 cpu->memory_rw(cpu, cpu->mem, arg1, charbuf,
1314 arg2, MEM_WRITE, CACHE_DATA);
1315
1316 free(charbuf);
1317 }
1318 break;
1319
1320 case ULTRIX_SYS_write:
1321 descr = arg0;
1322 mipsbuf = arg1;
1323 length = arg2;
1324 debug("[ write(%i,0x%llx,%lli) ]\n",
1325 (int)descr, (long long)mipsbuf, (long long)length);
1326
1327 if (length != 0) {
1328 charbuf = malloc(length);
1329 if (charbuf == NULL) {
1330 fprintf(stderr, "out of memory in "
1331 "useremul__ultrix()\n");
1332 exit(1);
1333 }
1334
1335 /* TODO: address validity check */
1336 cpu->memory_rw(cpu, cpu->mem, mipsbuf, charbuf,
1337 length, MEM_READ, CACHE_DATA);
1338
1339 result_low = write(descr, charbuf, length);
1340 if ((int64_t)result_low < 0) {
1341 error_code = errno;
1342 error_flag = 1;
1343 }
1344 free(charbuf);
1345 }
1346 break;
1347
1348 case ULTRIX_SYS_open:
1349 charbuf = get_userland_string(cpu, arg0);
1350 debug("[ open(\"%s\", 0x%llx, 0x%llx) ]\n",
1351 charbuf, (long long)arg1, (long long)arg2);
1352
1353 result_low = open((char *)charbuf, arg1, arg2);
1354 if ((int64_t)result_low < 0) {
1355 error_flag = 1;
1356 error_code = errno;
1357 }
1358 free(charbuf);
1359 break;
1360
1361 case ULTRIX_SYS_close:
1362 descr = arg0;
1363 debug("[ close(%i) ]\n", (int)descr);
1364
1365 /* Special case because some Ultrix programs tend
1366 to close low descriptors: */
1367 if (descr <= 2) {
1368 error_flag = 1;
1369 error_code = 2; /* TODO: Ultrix ENOENT error code */
1370 break;
1371 }
1372
1373 error_code = close(descr);
1374 if (error_code != 0)
1375 error_flag = 1;
1376 break;
1377
1378 case ULTRIX_SYS_break:
1379 useremul_break(cpu, arg0);
1380 break;
1381
1382 case ULTRIX_SYS_sync:
1383 useremul_sync(cpu);
1384 break;
1385
1386 case ULTRIX_SYS_getuid:
1387 result_low = useremul_getuid(cpu);
1388 break;
1389
1390 case ULTRIX_SYS_getgid:
1391 debug("[ getgid() ]\n");
1392 result_low = getgid();
1393 break;
1394
1395 case ULTRIX_SYS_dup:
1396 debug("[ dup(%i) ]\n", (int)arg0);
1397 result_low = dup(arg0);
1398 if ((int64_t)result_low < 0) {
1399 error_code = errno;
1400 error_flag = 1;
1401 }
1402 break;
1403
1404 case ULTRIX_SYS_socket:
1405 debug("[ socket(%i,%i,%i) ]\n",
1406 (int)arg0, (int)arg1, (int)arg2);
1407 result_low = socket(arg0,arg1,arg2);
1408 if ((int64_t)result_low < 0) {
1409 error_code = errno;
1410 error_flag = 1;
1411 }
1412 break;
1413
1414 case ULTRIX_SYS_select:
1415 debug("[ select(%i,0x%x,0x%x,0x%x,0x%x): TODO ]\n",
1416 (int)arg0, (int)arg1, (int)arg2, (int)arg3, (int)stack0);
1417
1418 /* TODO */
1419 {
1420 fd_set fdset;
1421 FD_SET(3, &fdset);
1422 result_low = select(4, &fdset, NULL, NULL, NULL);
1423 }
1424 break;
1425
1426 case ULTRIX_SYS_setsockopt:
1427 debug("[ setsockopt(%i,%i,%i,0x%x,%i): TODO ]\n",
1428 (int)arg0, (int)arg1, (int)arg2, (int)arg3, (int)stack0);
1429 /* TODO: len is not 4, len is stack0? */
1430 charbuf = get_userland_buf(cpu, arg3, 4);
1431 /* TODO: endianness of charbuf, etc */
1432 result_low = setsockopt(arg0, arg1, arg2, (void *)charbuf, 4);
1433 if ((int64_t)result_low < 0) {
1434 error_code = errno;
1435 error_flag = 1;
1436 }
1437 free(charbuf);
1438 printf("setsockopt!!!! res = %i error=%i\n",
1439 (int)result_low, (int)error_code);
1440 break;
1441
1442 case ULTRIX_SYS_connect:
1443 debug("[ connect(%i,0x%x,%i) ]\n",
1444 (int)arg0, (int)arg1, (int)arg2);
1445 charbuf = get_userland_buf(cpu, arg1, arg2);
1446 result_low = connect(arg0, (void *)charbuf, arg2);
1447 if ((int64_t)result_low < 0) {
1448 error_code = errno;
1449 error_flag = 1;
1450 }
1451 printf("connect!!!! res = %i error=%i\n",
1452 (int)result_low, (int)error_code);
1453 free(charbuf);
1454 break;
1455
1456 case ULTRIX_SYS_fcntl:
1457 debug("[ fcntl(%i,%i,0x%x): TODO ]\n",
1458 (int)arg0, (int)arg1, (int)arg2);
1459 /* TODO: how about that third argument? */
1460 result_low = fcntl(arg0, arg1, arg2);
1461 if ((int64_t)result_low < 0) {
1462 error_code = errno;
1463 error_flag = 1;
1464 }
1465 printf("fcntl!!!! res = %i error=%i\n",
1466 (int)result_low, (int)error_code);
1467 break;
1468
1469 case ULTRIX_SYS_stat43:
1470 charbuf = get_userland_string(cpu, arg0);
1471 debug("[ stat(\"%s\", 0x%llx): TODO ]\n",
1472 charbuf, (long long)arg1);
1473
1474 if (arg1 != 0) {
1475 struct stat st;
1476 result_low = stat((char *)charbuf, &st);
1477 if ((int64_t)result_low < 0) {
1478 error_flag = 1;
1479 error_code = errno;
1480 } else {
1481 /* Fill in the Ultrix stat struct at arg1: */
1482
1483 /* TODO */
1484 }
1485 } else {
1486 error_flag = 1;
1487 error_code = 1111; /* TODO: ultrix ENOMEM? */
1488 }
1489 free(charbuf);
1490 break;
1491
1492 case ULTRIX_SYS_fstat:
1493 result_low = useremul_fstat(cpu, &error_code, arg0, arg1);
1494 break;
1495
1496 case ULTRIX_SYS_getpagesize:
1497 debug("[ getpagesize() ]\n");
1498 result_low = 4096;
1499 break;
1500
1501 case ULTRIX_SYS_getdtablesize:
1502 debug("[ getdtablesize() ]\n");
1503 result_low = getdtablesize();
1504 break;
1505
1506 case ULTRIX_SYS_gethostname:
1507 debug("[ gethostname(0x%llx,%lli) ]\n",
1508 (long long)arg0, (long long)arg1);
1509 result_low = 0;
1510 if (arg1 != 0 && arg1 < 500000) {
1511 unsigned char *buf = malloc(arg1);
1512 unsigned int i;
1513
1514 result_low = gethostname((char *)buf, arg1);
1515 for (i = 0; i<arg1 && i < arg1; i++)
1516 cpu->memory_rw(cpu, cpu->mem, arg0 + i,
1517 &buf[i], 1, MEM_WRITE, CACHE_NONE);
1518
1519 free(buf);
1520 } else {
1521 error_flag = 1;
1522 error_code = 5555; /* TODO */ /* ENOMEM */
1523 }
1524 break;
1525
1526 case ULTRIX_SYS_writev:
1527 descr = arg0;
1528 debug("[ writev(%lli,0x%llx,%lli) ]\n",
1529 (long long)arg0, (long long)arg1, (long long)arg2);
1530
1531 if (arg1 != 0) {
1532 unsigned int i, total = 0;
1533
1534 for (i=0; i<arg2; i++) {
1535 uint32_t iov_base, iov_len;
1536 iov_base = load_32bit_word(cpu,
1537 arg1 + 8*i + 0); /* char * */
1538 iov_len = load_32bit_word(cpu,
1539 arg1 + 8*i + 4); /* size_t */
1540
1541 if (iov_len != 0) {
1542 unsigned char *charbuf =
1543 malloc(iov_len);
1544 if (charbuf == NULL) {
1545 fprintf(stderr, "out of memory"
1546 " in useremul__ultrix()\n");
1547 exit(1);
1548 }
1549
1550 /* TODO: address validity check */
1551 cpu->memory_rw(cpu, cpu->mem, (uint64_t)
1552 iov_base, charbuf, iov_len,
1553 MEM_READ, CACHE_DATA);
1554 total += write(descr, charbuf, iov_len);
1555 free(charbuf);
1556 }
1557 }
1558
1559 result_low = total;
1560 }
1561 break;
1562
1563 case ULTRIX_SYS_gethostid:
1564 debug("[ gethostid() ]\n");
1565 /* This is supposed to return a unique 32-bit host id. */
1566 result_low = 0x12345678;
1567 break;
1568
1569 case ULTRIX_SYS_gettimeofday:
1570 debug("[ gettimeofday(0x%llx,0x%llx) ]\n",
1571 (long long)arg0, (long long)arg1);
1572 result_low = gettimeofday(&tv, &tz);
1573 if (result_low) {
1574 error_flag = 1;
1575 error_code = errno;
1576 } else {
1577 if (arg0 != 0) {
1578 /* Store tv.tv_sec and tv.tv_usec
1579 as 'long' (32-bit) values: */
1580 store_32bit_word(cpu, arg0 + 0, tv.tv_sec);
1581 store_32bit_word(cpu, arg0 + 4, tv.tv_usec);
1582 }
1583 if (arg1 != 0) {
1584 /* Store tz.tz_minuteswest and
1585 tz.tz_dsttime as 'long' (32-bit) values: */
1586 store_32bit_word(cpu, arg1 + 0,
1587 tz.tz_minuteswest);
1588 store_32bit_word(cpu, arg1 + 4, tz.tz_dsttime);
1589 }
1590 }
1591 break;
1592
1593 default:
1594 fatal("[ UNIMPLEMENTED ultrix syscall %i ]\n", sysnr);
1595 error_flag = 1;
1596 error_code = 78; /* ENOSYS */
1597 }
1598
1599 /*
1600 * Ultrix/mips return values:
1601 *
1602 * TODO
1603 *
1604 * a3 is 0 if the syscall was ok, otherwise 1.
1605 * v0 (and sometimes v1) contain the result value.
1606 */
1607 cpu->cd.mips.gpr[MIPS_GPR_A3] = error_flag;
1608 if (error_flag)
1609 cpu->cd.mips.gpr[MIPS_GPR_V0] = error_code;
1610 else
1611 cpu->cd.mips.gpr[MIPS_GPR_V0] = result_low;
1612
1613 if (result_high_set)
1614 cpu->cd.mips.gpr[MIPS_GPR_V1] = result_high;
1615
1616 /* TODO */
1617 }
1618
1619
1620 /*
1621 * useremul_name_to_useremul():
1622 *
1623 * Example:
1624 * Input: name = "netbsd/pmax"
1625 * Output: sets *arch = ARCH_MIPS, *machine_name = "NetBSD/pmax",
1626 * and *cpu_name = "R3000".
1627 */
1628 void useremul_name_to_useremul(struct cpu *cpu, char *name, int *arch,
1629 char **machine_name, char **cpu_name)
1630 {
1631 struct syscall_emul *sep;
1632
1633 sep = first_syscall_emul;
1634
1635 while (sep != NULL) {
1636 if (strcasecmp(name, sep->name) == 0) {
1637 if (cpu_family_ptr_by_number(sep->arch) == NULL) {
1638 printf("\nSupport for the CPU family needed"
1639 " for '%s' userland emulation was not"
1640 " enabled at configuration time.\n",
1641 sep->name);
1642 exit(1);
1643 }
1644
1645 if (cpu != NULL)
1646 cpu->useremul_syscall = sep->f;
1647
1648 if (arch != NULL)
1649 *arch = sep->arch;
1650
1651 if (machine_name != NULL) {
1652 *machine_name = strdup(sep->name);
1653 if (*machine_name == NULL) {
1654 printf("out of memory\n");
1655 exit(1);
1656 }
1657 }
1658
1659 if (cpu_name != NULL) {
1660 *cpu_name = strdup(sep->cpu_name);
1661 if (*cpu_name == NULL) {
1662 printf("out of memory\n");
1663 exit(1);
1664 }
1665 }
1666 return;
1667 }
1668
1669 sep = sep->next;
1670 }
1671
1672 fatal("Unknown userland emulation '%s'\n", name);
1673 exit(1);
1674 }
1675
1676
1677 /*
1678 * add_useremul():
1679 *
1680 * For internal use, from useremul_init() only. Adds an emulation mode.
1681 */
1682 static void add_useremul(char *name, int arch, char *cpu_name,
1683 void (*f)(struct cpu *, uint32_t),
1684 void (*setup)(struct cpu *, int, char **))
1685 {
1686 struct syscall_emul *sep;
1687
1688 sep = malloc(sizeof(struct syscall_emul));
1689 if (sep == NULL) {
1690 printf("add_useremul(): out of memory\n");
1691 exit(1);
1692 }
1693 memset(sep, 0, sizeof(sep));
1694
1695 sep->name = name;
1696 sep->arch = arch;
1697 sep->cpu_name = cpu_name;
1698 sep->f = f;
1699 sep->setup = setup;
1700
1701 sep->next = first_syscall_emul;
1702 first_syscall_emul = sep;
1703 }
1704
1705
1706 /*
1707 * useremul_list_emuls():
1708 *
1709 * List all available userland emulation modes. (Actually, only those which
1710 * have CPU support enabled.)
1711 */
1712 void useremul_list_emuls(void)
1713 {
1714 struct syscall_emul *sep;
1715 int iadd = 8;
1716
1717 sep = first_syscall_emul;
1718
1719 if (sep == NULL)
1720 return;
1721
1722 debug("The following userland-only (syscall) emulation modes are"
1723 " available:\n\n");
1724 debug_indentation(iadd);
1725
1726 while (sep != NULL) {
1727 if (cpu_family_ptr_by_number(sep->arch) != NULL) {
1728 debug("%s (default CPU \"%s\")\n",
1729 sep->name, sep->cpu_name);
1730 }
1731
1732 sep = sep->next;
1733 }
1734
1735 debug_indentation(-iadd);
1736 debug("\n(Most of these modes are bogus.)\n\n");
1737 }
1738
1739
1740 /*
1741 * useremul_init():
1742 *
1743 * This function should be called before any other useremul_*() function
1744 * is used.
1745 */
1746 void useremul_init(void)
1747 {
1748 /* Note: These are in reverse alphabetic order: */
1749
1750 add_useremul("Ultrix", ARCH_MIPS, "R3000",
1751 useremul__ultrix, useremul__ultrix_setup);
1752
1753 add_useremul("NetBSD/powerpc", ARCH_PPC, "PPC750",
1754 useremul__netbsd, useremul__netbsd_setup);
1755
1756 add_useremul("NetBSD/pmax", ARCH_MIPS, "R3000",
1757 useremul__netbsd, useremul__netbsd_setup);
1758
1759 add_useremul("NetBSD/arm", ARCH_ARM, "SA1110",
1760 useremul__netbsd, useremul__netbsd_setup);
1761
1762 add_useremul("NetBSD/amd64", ARCH_X86, "AMD64",
1763 useremul__netbsd, useremul__netbsd_setup);
1764
1765 add_useremul("NetBSD/alpha", ARCH_ALPHA, "Alpha",
1766 useremul__netbsd, useremul__netbsd_setup);
1767
1768 add_useremul("Linux/PPC64", ARCH_PPC, "PPC970",
1769 useremul__linux, useremul__linux_setup);
1770
1771 add_useremul("FreeBSD/Alpha", ARCH_ALPHA, "Alpha",
1772 useremul__freebsd, useremul__freebsd_setup);
1773 }
1774

  ViewVC Help
Powered by ViewVC 1.1.26