/[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 34 - (show annotations)
Mon Oct 8 16:21:17 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 43974 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1480 2007/02/19 01:34:42 debug Exp $
20061029	Changing usleep(1) calls in the debugger to usleep(10000)
20061107	Adding a new disk image option (-d o...) which sets the ISO9660
		filesystem base offset; also making some other hacks to allow
		NetBSD/dreamcast and homebrew demos/games to boot directly
		from a filesystem image.
		Moving Dreamcast-specific stuff in the documentation to its
		own page (dreamcast.html).
		Adding a border to the Dreamcast PVR framebuffer.
20061108	Adding a -T command line option (again?), for halting the
		emulator on unimplemented memory accesses.
20061109	Continuing on various SH4 and Dreamcast related things.
		The emulator should now halt on more unimplemented device
		accesses, instead of just printing a warning, forcing me to
		actually implement missing stuff :)
20061111	Continuing on SH4 and Dreamcast stuff.
		Adding a bogus Landisk (SH4) machine mode.
20061112	Implementing some parts of the Dreamcast GDROM device. With
		some ugly hacks, NetBSD can (barely) mount an ISO image.
20061113	NetBSD/dreamcast now starts booting from the Live CD image,
		but crashes randomly quite early on in the boot process.
20061122	Beginning on a skeleton interrupt.h and interrupt.c for the
		new interrupt subsystem.
20061124	Continuing on the new interrupt system; taking the first steps
		to attempt to connect CPUs (SuperH and MIPS) and devices
		(dev_cons and SH4 timer interrupts) to it. Many things will
		probably break from now on.
20061125	Converting dev_ns16550, dev_8253 to the new interrupt system.
		Attempting to begin to convert the ISA bus.
20061130	Incorporating a patch from Brian Foley for the configure
		script, which checks for X11 libs in /usr/X11R6/lib64 (which
		is used on some Linux systems).
20061227	Adding a note in the man page about booting from Dreamcast
		CDROM images (i.e. that no external kernel is needed).
20061229	Continuing on the interrupt system rewrite: beginning to
		convert more devices, adding abort() calls for legacy interrupt
		system calls so that everything now _has_ to be rewritten!
		Almost all machine modes are now completely broken.
20061230	More progress on removing old interrupt code, mostly related
		to the ISA bus + devices, the LCA bus (on AlphaBook1), and
		the Footbridge bus (for CATS). And some minor PCI stuff.
		Connecting the ARM cpu to the new interrupt system.
		The CATS, NetWinder, and QEMU_MIPS machine modes now work with
		the new interrupt system :)
20061231	Connecting PowerPC CPUs to the new interrupt system.
		Making PReP machines (IBM 6050) work again.
		Beginning to convert the GT PCI controller (for e.g. Malta
		and Cobalt emulation). Some things work, but not everything.
		Updating Copyright notices for 2007.
20070101	Converting dev_kn02 from legacy style to devinit; the 3max
		machine mode now works with the new interrupt system :-]
20070105	Beginning to convert the SGI O2 machine to the new interrupt
		system; finally converting O2 (IP32) devices to devinit, etc.
20070106	Continuing on the interrupt system redesign/rewrite; KN01
		(PMAX), KN230, and Dreamcast ASIC interrupts should work again,
		moving out stuff from machine.h and devices.h into the
		corresponding devices, beginning the rewrite of i80321
		interrupts, etc.
20070107	Beginning on the rewrite of Eagle interrupt stuff (PReP, etc).
20070117	Beginning the rewrite of Algor (V3) interrupts (finally
		changing dev_v3 into devinit style).
20070118	Removing the "bus" registry concept from machine.h, because
		it was practically meaningless.
		Continuing on the rewrite of Algor V3 ISA interrupts.
20070121	More work on Algor interrupts; they are now working again,
		well enough to run NetBSD/algor. :-)
20070122	Converting VR41xx (HPCmips) interrupts. NetBSD/hpcmips
		can be installed using the new interrupt system :-)
20070123	Making the testmips mode work with the new interrupt system.
20070127	Beginning to convert DEC5800 devices to devinit, and to the
		new interrupt system.
		Converting Playstation 2 devices to devinit, and converting
		the interrupt system. Also fixing a severe bug: the interrupt
		mask register on Playstation 2 is bitwise _toggled_ on writes.
20070128	Removing the dummy NetGear machine mode and the 8250 device
		(which was only used by the NetGear machine).
		Beginning to convert the MacPPC GC (Grand Central) interrupt
		controller to the new interrupt system.
		Converting Jazz interrupts (PICA61 etc.) to the new interrupt
		system. NetBSD/arc can be installed again :-)
		Fixing the JAZZ timer (hardcoding it at 100 Hz, works with
		NetBSD and it is better than a completely dummy timer as it
		was before).
		Converting dev_mp to the new interrupt system, although I
		haven't had time to actually test it yet.
		Completely removing src/machines/interrupts.c, cpu_interrupt
		and cpu_interrupt_ack in src/cpu.c, and
		src/include/machine_interrupts.h! Adding fatal error messages
		+ abort() in the few places that are left to fix.
		Converting dev_z8530 to the new interrupt system.
		FINALLY removing the md_int struct completely from the
		machine struct.
		SH4 fixes (adding a PADDR invalidation in the ITLB replacement
		code in memory_sh.c); the NetBSD/dreamcast LiveCD now runs
		all the way to the login prompt, and can be interacted with :-)
		Converting the CPC700 controller (PCI and interrupt controller
		for PM/PPC) to the new interrupt system.
20070129	Fixing MACE ISA interrupts (SGI IP32 emulation). Both NetBSD/
		sgimips' and OpenBSD/sgi's ramdisk kernels can now be
		interacted with again.
20070130	Moving out the MIPS multi_lw and _sw instruction combinations
		so that they are auto-generated at compile time instead.
20070131	Adding detection of amd64/x86_64 hosts in the configure script,
		for doing initial experiments (again :-) with native code
		generation.
		Adding a -k command line option to set the size of the dyntrans
		cache, and a -B command line option to disable native code
		generation, even if GXemul was compiled with support for
		native code generation for the specific host CPU architecture.
20070201	Experimenting with a skeleton for native code generation.
		Changing the default behaviour, so that native code generation
		is now disabled by default, and has to be enabled by using
		-b on the command line.
20070202	Continuing the native code generation experiments.
		Making PCI interrupts work for Footbridge again.
20070203	More native code generation experiments.
		Removing most of the native code generation experimental code,
		it does not make sense to include any quick hacks like this.
		Minor cleanup/removal of some more legacy MIPS interrupt code.
20070204	Making i80321 interrupts work again (for NetBSD/evbarm etc.),
		and fixing the timer at 100 Hz.
20070206	Experimenting with removing the wdc interrupt slowness hack.
20070207	Lowering the number of dyntrans TLB entries for MIPS from
		192 to 128, resulting in a minor speed improvement.
		Minor optimization to the code invalidation routine in
		cpu_dyntrans.c.
20070208	Increasing (experimentally) the nr of dyntrans instructions per
		loop from 60 to 120.
20070210	Commenting out (experimentally) the dyntrans_device_danger
		detection in memory_rw.c.
		Changing the testmips and baremips machines to use a revision 2
		MIPS64 CPU by default, instead of revision 1.
		Removing the dummy i960, IA64, x86, AVR32, and HP PA-RISC
		files, the PC bios emulation, and the Olivetti M700 (ARC) and
		db64360 emulation modes.
20070211	Adding an "mp" demo to the demos directory, which tests the
		SMP functionality of the testmips machine.
		Fixing PReP interrupts some more. NetBSD/prep now boots again.
20070216	Adding a "nop workaround" for booting Mach/PMAX to the
		documentation; thanks to Artur Bujdoso for the values.
		Converting more of the MacPPC interrupt stuff to the new
		system.
		Beginning to convert BeBox interrupts to the new system.
		PPC603e should NOT have the PPC_NO_DEC flag! Removing it.
		Correcting BeBox clock speed (it was set to 100 in the NetBSD
		bootinfo block, but should be 33000000/4), allowing NetBSD
		to start without using the (incorrect) PPC_NO_DEC hack.
20070217	Implementing (slow) AltiVec vector loads and stores, allowing
		NetBSD/macppc to finally boot using the GENERIC kernel :-)
		Updating the documentation with install instructions for
		NetBSD/macppc.
20070218-19	Regression testing for the release.

==============  RELEASE 0.4.4  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26