/[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 12 - (show annotations)
Mon Oct 8 16:18:38 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 42817 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.905 2005/08/16 09:16:24 debug Exp $
20050628	Continuing the work on the ARM translation engine. end_of_page
		works. Experimenting with load/store translation caches
		(virtual -> physical -> host).
20050629	More ARM stuff (memory access translation cache, mostly). This
		might break a lot of stuff elsewhere, probably some MIPS-
		related translation things.
20050630	Many load/stores are now automatically generated and included
		into cpu_arm_instr.c; 1024 functions in total (!).
		Fixes based on feedback from Alec Voropay: only print 8 hex
		digits instead of 16 in some cases when emulating 32-bit
		machines; similar 8 vs 16 digit fix for breakpoint addresses;
		4Kc has 16 TLB entries, not 48; the MIPS config select1
		register is now printed with "reg ,0".
		Also changing many other occurances of 16 vs 8 digit output.
		Adding cache associativity fields to mips_cpu_types.h; updating
		some other cache fields; making the output of
		mips_cpu_dumpinfo() look nicer.
		Generalizing the bintrans stuff for device accesses to also
		work with the new translation system. (This might also break
		some MIPS things.)
		Adding multi-load/store instructions to the ARM disassembler
		and the translator, and some optimizations of various kinds.
20050701	Adding a simple dev_disk (it can read/write sectors from
		disk images).
20050712	Adding dev_ether (a simple ethernet send/receive device).
		Debugger command "ninstrs" for toggling show_nr_of_instructions
		during runtime.
		Removing the framebuffer logo.
20050713	Continuing on dev_ether.
		Adding a dummy cpu_alpha (again).
20050714	More work on cpu_alpha.
20050715	More work on cpu_alpha. Many instructions work, enough to run
		a simple framebuffer fill test (similar to the ARM test).
20050716	More Alpha stuff.
20050717	Minor updates (Alpha stuff).
20050718	Minor updates (Alpha stuff).
20050719	Generalizing some Alpha instructions.
20050720	More Alpha-related updates.
20050721	Continuing on cpu_alpha. Importing rpb.h from NetBSD/alpha.
20050722	Alpha-related updates: userland stuff (Hello World using
		write() compiled statically for FreeBSD/Alpha runs fine), and
		more instructions are now implemented.
20050723	Fixing ldq_u and stq_u.
		Adding more instructions (conditional moves, masks, extracts,
		shifts).
20050724	More FreeBSD/Alpha userland stuff, and adding some more
		instructions (inserts).
20050725	Continuing on the Alpha stuff. (Adding dummy ldt/stt.)
		Adding a -A command line option to turn off alignment checks
		in some cases (for translated code).
		Trying to remove the old bintrans code which updated the pc
		and nr_of_executed_instructions for every instruction.
20050726	Making another attempt att removing the pc/nr of instructions
		code. This time it worked, huge performance increase for
		artificial test code, but performance loss for real-world
		code :-( so I'm scrapping that code for now.
		Tiny performance increase on Alpha (by using ret instead of
		jmp, to play nice with the Alpha's branch prediction) for the
		old MIPS bintrans backend.
20050727	Various minor fixes and cleanups.
20050728	Switching from a 2-level virtual to host/physical translation
		system for ARM emulation, to a 1-level translation.
		Trying to switch from 2-level to 1-level for the MIPS bintrans
		system as well (Alpha only, so far), but there is at least one
		problem: caches and/or how they work with device mappings.
20050730	Doing the 2-level to 1-level conversion for the i386 backend.
		The cache/device bug is still there for R2K/3K :(
		Various other minor updates (Malta etc).
		The mc146818 clock now updates the UIP bit in a way which works
		better with Linux for at least sgimips and Malta emulation.
		Beginning the work on refactoring the dyntrans system.
20050731	Continuing the dyntrans refactoring.
		Fixing a small but serious host alignment bug in memory_rw.
		Adding support for big-endian load/stores to the i386 bintrans
		backend.
		Another minor i386 bintrans backend update: stores from the
		zero register are now one (or two) loads shorter.
		The slt and sltu instructions were incorrectly implemented for
		the i386 backend; only using them for 32-bit mode for now.
20050801	Continuing the dyntrans refactoring.
		Cleanup of the ns16550 serial controller (removing unnecessary
		code).
		Bugfix (memory corruption bug) in dev_gt, and a patch/hack from
		Alec Voropay for Linux/Malta.
20050802	More cleanup/refactoring of the dyntrans subsystem: adding
		phys_page pointers to the lookup tables, for quick jumps
		between translated pages.
		Better fix for the ns16550 device (but still no real FIFO
		functionality).
		Converting cpu_ppc to the new dyntrans system. This means that
		I will have to start from scratch with implementing each
		instruction, and figure out how to implement dual 64/32-bit
		modes etc.
		Removing the URISC CPU family, because it was useless.
20050803	When selecting a machine type, the main type can now be omitted
		if the subtype name is unique. (I.e. -E can be omitted.)
		Fixing a dyntrans/device update bug. (Writes to offset 0 of
		a device could sometimes go unnoticed.)
		Adding an experimental "instruction combination" hack for
		ARM for memset-like byte fill loops.
20050804	Minor progress on cpu_alpha and related things.
		Finally fixing the MIPS dmult/dmultu bugs.
		Fixing some minor TODOs.
20050805	Generalizing the 8259 PIC. It now also works with Cobalt
		and evbmips emulation, in addition to the x86 hack.
		Finally converting the ns16550 device to use devinit.
		Continuing the work on the dyntrans system. Thinking about
		how to add breakpoints.
20050806	More dyntrans updates. Breakpoints seem to work now.
20050807	Minor updates: cpu_alpha and related things; removing
		dev_malta (as it isn't used any more).
		Dyntrans: working on general "show trace tree" support.
		The trace tree stuff now works with both the old MIPS code and
		with newer dyntrans modes. :)
		Continuing on Alpha-related stuff (trying to get *BSD to boot
		a bit further, adding more instructions, etc).
20050808	Adding a dummy IA64 cpu family, and continuing the refactoring
		of the dyntrans system.
		Removing the regression test stuff, because it was more or
		less useless.
		Adding loadlinked/storeconditional type instructions to the
		Alpha emulation. (Needed for Linux/alpha. Not very well tested
		yet.)
20050809	The function call trace tree now prints a per-function nr of
		arguments. (Semi-meaningless, since that data isn't read yet
		from the ELFs; some hardcoded symbols such as memcpy() and
		strlen() work fine, though.)
		More dyntrans refactoring; taking out more of the things that
		are common to all cpu families.
20050810	Working on adding support for "dual mode" for PPC dyntrans
		(i.e. both 64-bit and 32-bit modes).
		(Re)adding some simple PPC instructions.
20050811	Adding a dummy M68K cpu family. The dyntrans system isn't ready
		for variable-length ISAs yet, so it's completely bogus so far.
		Re-adding more PPC instructions.
		Adding a hack to src/file.c which allows OpenBSD/mac68k a.out
		kernels to be loaded.
		Beginning to add PPC loads/stores. So far they only work in
		32-bit mode.
20050812	The configure file option "add_remote" now accepts symbolic
		host names, in addition to numeric IPv4 addresses.
		Re-adding more PPC instructions.
20050814	Continuing to port back more PPC instructions.
		Found and fixed the cache/device write-update bug for 32-bit
		MIPS bintrans. :-)
		Triggered a really weird and annoying bug in Compaq's C
		compiler; ccc sometimes outputs code which loads from an
		address _before_ checking whether the pointer was NULL or not.
		(I'm not sure how to handle this problem.)
20050815	Removing all of the old x86 instruction execution code; adding
		a new (dummy) dyntrans module for x86.
		Taking the first steps to extend the dyntrans system to support
		variable-length instructions.
		Slowly preparing for the next release.
20050816	Adding a dummy SPARC cpu module.
		Minor updates (documentation etc) for the release.

==============  RELEASE 0.3.5  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26