/[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 32 - (show annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 44149 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1421 2006/11/06 05:32:37 debug Exp $
20060816	Adding a framework for emulated/virtual timers (src/timer.c),
		using only setitimer().
		Rewriting the mc146818 to use the new timer framework.
20060817	Adding a call to gettimeofday() every now and then (once every
		second, at the moment) to resynch the timer if it drifts.
		Beginning to convert the ISA timer interrupt mechanism (8253
		and 8259) to use the new timer framework.
		Removing the -I command line option.
20060819	Adding the -I command line option again, with new semantics.
		Working on Footbridge timer interrupts; NetBSD/NetWinder and
		NetBSD/CATS now run at correct speed, but unfortunately with
		HUGE delays during bootup.
20060821	Some minor m68k updates. Adding the first instruction: nop. :)
		Minor Alpha emulation updates.
20060822	Adding a FreeBSD development specific YAMON environment
		variable ("khz") (as suggested by Bruce M. Simpson).
		Moving YAMON environment variable initialization from
		machine_evbmips.c into promemul/yamon.c, and adding some more
		variables.
		Continuing on the LCA PCI bus controller (for Alpha machines).
20060823	Continuing on the timer stuff: experimenting with MIPS count/
		compare interrupts connected to the timer framework.
20060825	Adding bogus SCSI commands 0x51 (SCSICDROM_READ_DISCINFO) and
		0x52 (SCSICDROM_READ_TRACKINFO) to the SCSI emulation layer,
		to allow NetBSD/pmax 4.0_BETA to be installed from CDROM.
		Minor updates to the LCA PCI controller.
20060827	Implementing a CHIP8 cpu mode, and a corresponding CHIP8
		machine, for fun. Disassembly support for all instructions,
		and most of the common instructions have been implemented: mvi,
		mov_imm, add_imm, jmp, rand, cls, sprite, skeq_imm, jsr,
		skne_imm, bcd, rts, ldr, str, mov, or, and, xor, add, sub,
		font, ssound, sdelay, gdelay, bogus skup/skpr, skeq, skne.
20060828	Beginning to convert the CHIP8 cpu in the CHIP8 machine to a
		(more correct) RCA 180x cpu. (Disassembly for all 1802
		instructions has been implemented, but no execution yet, and
		no 1805 extended instructions.)
20060829	Minor Alpha emulation updates.
20060830	Beginning to experiment a little with PCI IDE for SGI O2.
		Fixing the cursor key mappings for MobilePro 770 emulation.
		Fixing the LK201 warning caused by recent NetBSD/pmax.
		The MIPS R41xx standby, suspend, and hibernate instructions now
		behave like the RM52xx/MIPS32/MIPS64 wait instruction.
		Fixing dev_wdc so it calculates correct (64-bit) offsets before
		giving them to diskimage_access().
20060831	Continuing on Alpha emulation (OSF1 PALcode).
20060901	Minor Alpha updates; beginning on virtual memory pagetables.
		Removed the limit for max nr of devices (in preparation for
		allowing devices' base addresses to be changed during runtime).
		Adding a hack for MIPS [d]mfc0 select 0 (except the count
		register), so that the coproc register is simply copied.
		The MIPS suspend instruction now exits the emulator, instead
		of being treated as a wait instruction (this causes NetBSD/
		hpcmips to get correct 'halt' behavior).
		The VR41xx RTC now returns correct time.
		Connecting the VR41xx timer to the timer framework (fixed at
		128 Hz, for now).
		Continuing on SPARC emulation, adding more instructions:
		restore, ba_xcc, ble. The rectangle drawing demo works :)
		Removing the last traces of the old ENABLE_CACHE_EMULATION
		MIPS stuff (not usable with dyntrans anyway).
20060902	Splitting up src/net.c into several smaller files in its own
		subdirectory (src/net/).
20060903	Cleanup of the files in src/net/, to make them less ugly.
20060904	Continuing on the 'settings' subsystem.
		Minor progress on the SPARC emulation mode.
20060905	Cleanup of various things, and connecting the settings
		infrastructure to various subsystems (emul, machine, cpu, etc).
		Changing the lk201 mouse update routine to not rely on any
		emulated hardware framebuffer cursor coordinates, but instead
		always do (semi-usable) relative movements.
20060906	Continuing on the lk201 mouse stuff. Mouse behaviour with
		multiple framebuffers (which was working in Ultrix) is now
		semi-broken (but it still works, in a way).
		Moving the documentation about networking into its own file
		(networking.html), and refreshing it a bit. Adding an example
		of how to use ethernet frame direct-access (udp_snoop).
20060907	Continuing on the settings infrastructure.
20060908	Minor updates to SH emulation: for 32-bit emulation: delay
		slots and the 'jsr @Rn' instruction. I'm putting 64-bit SH5 on
		ice, for now.
20060909-10	Implementing some more 32-bit SH instructions. Removing the
		64-bit mode completely. Enough has now been implemented to run
		the rectangle drawing demo. :-)
20060912	Adding more SH instructions.
20060916	Continuing on SH emulation (some more instructions: div0u,
		div1, rotcl/rotcr, more mov instructions, dt, braf, sets, sett,
		tst_imm, dmuls.l, subc, ldc_rm_vbr, movt, clrt, clrs, clrmac).
		Continuing on the settings subsystem (beginning on reading/
		writing settings, removing bugs, and connecting more cpus to
		the framework).
20060919	More work on SH emulation; adding an ldc banked instruction,
		and attaching a 640x480 framebuffer to the Dreamcast machine
		mode (NetBSD/dreamcast prints the NetBSD copyright banner :-),
		and then panics).
20060920	Continuing on the settings subsystem.
20060921	Fixing the Footbridge timer stuff so that NetBSD/cats and
		NetBSD/netwinder boot up without the delays.
20060922	Temporarily hardcoding MIPS timer interrupt to 100 Hz. With
		'wait' support disabled, NetBSD/malta and Linux/malta run at
		correct speed.
20060923	Connecting dev_gt to the timer framework, so that NetBSD/cobalt
		runs at correct speed.
		Moving SH4-specific memory mapped registers into its own
		device (dev_sh4.c).
		Running with -N now prints "idling" instead of bogus nr of
		instrs/second (which isn't valid anyway) while idling.
20060924	Algor emulation should now run at correct speed.
		Adding disassembly support for some MIPS64 revision 2
		instructions: ext, dext, dextm, dextu.
20060926	The timer framework now works also when the MIPS wait
		instruction is used.
20060928	Re-implementing checks for coprocessor availability for MIPS
		cop0 instructions. (Thanks to Carl van Schaik for noticing the
		lack of cop0 availability checks.)
20060929	Implementing an instruction combination hack which treats
		NetBSD/pmax' idle loop as a wait-like instruction.
20060930	The ENTRYHI_R_MASK was missing in (at least) memory_mips_v2p.c,
		causing TLB lookups to sometimes succeed when they should have
		failed. (A big thank you to Juli Mallett for noticing the
		problem.)
		Adding disassembly support for more MIPS64 revision 2 opcodes
		(seb, seh, wsbh, jalr.hb, jr.hb, synci, ins, dins, dinsu,
		dinsm, dsbh, dshd, ror, dror, rorv, drorv, dror32). Also
		implementing seb, seh, dsbh, dshd, and wsbh.
		Implementing an instruction combination hack for Linux/pmax'
		idle loop, similar to the NetBSD/pmax case.
20061001	Changing the NetBSD/sgimips install instructions to extract
		files from an iso image, instead of downloading them via ftp.
20061002	More-than-31-bit userland addresses in memory_mips_v2p.c were
		not actually working; applying a fix from Carl van Schaik to
		enable them to work + making some other updates (adding kuseg
		support).
		Fixing hpcmips (vr41xx) timer initialization.
		Experimenting with O(n)->O(1) reduction in the MIPS TLB lookup
		loop. Seems to work both for R3000 and non-R3000.
20061003	Continuing a little on SH emulation (adding more control
		registers; mini-cleanup of memory_sh.c).
20061004	Beginning on a dev_rtc, a clock/timer device for the test
		machines; also adding a demo, and some documentation.
		Fixing a bug in SH "mov.w @(disp,pc),Rn" (the result wasn't
		sign-extended), and adding the addc and ldtlb instructions.
20061005	Contining on SH emulation: virtual to physical address
		translation, and a skeleton exception mechanism.
20061006	Adding more SH instructions (various loads and stores, rte,
		negc, muls.w, various privileged register-move instructions).
20061007	More SH instructions: various move instructions, trapa, div0s,
		float, fdiv, ftrc.
		Continuing on dev_rtc; removing the rtc demo.
20061008	Adding a dummy Dreamcast PROM module. (Homebrew Dreamcast
		programs using KOS libs need this.)
		Adding more SH instructions: "stc vbr,rn", rotl, rotr, fsca,
		fmul, fadd, various floating-point moves, etc. A 256-byte
		demo for Dreamcast runs :-)
20061012	Adding the SH "lds Rm,pr" and bsr instructions.
20061013	More SH instructions: "sts fpscr,rn", tas.b, and some more
		floating point instructions, cmp/str, and more moves.
		Adding a dummy dev_pvr (Dreamcast graphics controller).
20061014	Generalizing the expression evaluator (used in the built-in
		debugger) to support parentheses and +-*/%^&|.
20061015	Removing the experimental tlb index hint code in
		mips_memory_v2p.c, since it didn't really have any effect.
20061017	Minor SH updates; adding the "sts pr,Rn", fcmp/gt, fneg,
		frchg, and some other instructions. Fixing missing sign-
		extension in an 8-bit load instruction.
20061019	Adding a simple dev_dreamcast_rtc.
		Implementing memory-mapped access to the SH ITLB/UTLB arrays.
20061021	Continuing on various SH and Dreamcast things: sh4 timers,
		debug messages for dev_pvr, fixing some virtual address
		translation bugs, adding the bsrf instruction.
		The NetBSD/dreamcast GENERIC_MD kernel now reaches userland :)
		Adding a dummy dev_dreamcast_asic.c (not really useful yet).
		Implementing simple support for Store Queues.
		Beginning on the PVR Tile Accelerator.
20061022	Generalizing the PVR framebuffer to support off-screen drawing,
		multiple bit-depths, etc. (A small speed penalty, but most
		likely worth it.)
		Adding more SH instructions (mulu.w, fcmp/eq, fsub, fmac,
		fschg, and some more); correcting bugs in "fsca" and "float".
20061024	Adding the SH ftrv (matrix * vector) instruction. Marcus
		Comstedt's "tatest" example runs :) (wireframe only).
		Correcting disassembly for SH floating point instructions that
		use the xd* registers.
		Adding the SH fsts instruction.
		In memory_device_dyntrans_access(), only the currently used
		range is now invalidated, and not the entire device range.
20061025	Adding a dummy AVR32 cpu mode skeleton.
20061026	Various Dreamcast updates; beginning on a Maple bus controller.
20061027	Continuing on the Maple bus. A bogus Controller, Keyboard, and
		Mouse can now be detected by NetBSD and KOS homebrew programs.
		Cleaning up the SH4 Timer Management Unit, and beginning on
		SH4 interrupts.
		Implementing the Dreamcast SYSASIC.
20061028	Continuing on the SYSASIC.
		Adding the SH fsqrt instruction.
		memory_sh.c now actually scans the ITLB.
		Fixing a bug in dev_sh4.c, related to associative writes into
		the memory-mapped UTLB array. NetBSD/dreamcast now reaches
		userland stably, and prints the "Terminal type?" message :-]
		Implementing enough of the Dreamcast keyboard to make NetBSD
		accept it for input.
		Enabling SuperH for stable (non-development) builds.
		Adding NetBSD/dreamcast to the documentation, although it
		doesn't support root-on-nfs yet.
20061029	Changing usleep(1) calls in the debugger to to usleep(10000)
		(according to Brian Foley, this makes GXemul run better on
		MacOS X).
		Making the Maple "Controller" do something (enough to barely
		interact with dcircus.elf).
20061030-31	Some progress on the PVR. More test programs start running (but
		with strange output).
		Various other SH4-related updates.
20061102	Various Dreamcast and SH4 updates; more KOS demos run now.
20061104	Adding a skeleton dev_mb8696x.c (the Dreamcast's LAN adapter).
20061105	Continuing on the MB8696x; NetBSD/dreamcast detects it as mbe0.
		Testing for the release.

==============  RELEASE 0.4.3  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26