/[gxemul]/upstream/0.4.4/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

Annotation of /upstream/0.4.4/src/useremul.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 32 - (hide annotations)
Mon Oct 8 16:20:58 2007 UTC (16 years, 6 months ago) by dpavlin
Original Path: trunk/src/useremul.c
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 dpavlin 2 /*
2 dpavlin 22 * Copyright (C) 2004-2006 Anders Gavare. All rights reserved.
3 dpavlin 2 *
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 dpavlin 32 * $Id: useremul.c,v 1.72 2006/09/30 05:57:07 debug Exp $
29 dpavlin 2 *
30     * Userland (syscall) emulation.
31     *
32     * TODO:
33     *
34 dpavlin 14 * environment passing for most emulation modes
35 dpavlin 2 *
36 dpavlin 14 * implement more syscalls
37     *
38 dpavlin 2 * 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 dpavlin 28 * 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 dpavlin 2 *
47 dpavlin 28 * Automagic errno translation!
48 dpavlin 2 *
49 dpavlin 28 * Memory allocation? mmap, munmap, mprotect, etc.
50     * mprotect = unmap in dyntrans...
51 dpavlin 2 *
52 dpavlin 28 * File descriptor (0,1,2) assumptions? Find and fix these?
53 dpavlin 2 *
54     *
55     * This module needs more cleanup.
56     * -------------------------------
57     *
58     *
59 dpavlin 28 * 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 dpavlin 2 */
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 dpavlin 12 #include <sys/resource.h>
75 dpavlin 2 #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 dpavlin 12 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 dpavlin 2 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 dpavlin 12 stack_top - stacksize, stacksize, "userstack", 0, 0);
208 dpavlin 2
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 dpavlin 14 case ARCH_ALPHA:
240     debug("useremul__netbsd_setup(): ALPHA: TODO\n");
241     break;
242    
243 dpavlin 12 case ARCH_ARM:
244     debug("useremul__netbsd_setup(): ARM: TODO\n");
245     break;
246    
247 dpavlin 2 case ARCH_PPC:
248 dpavlin 4 debug("useremul__netbsd_setup(): PPC: TODO\n");
249 dpavlin 2
250     /* What is a good stack pointer? TODO */
251     cpu->cd.ppc.gpr[1] = 0x7ffff000ULL;
252    
253     break;
254    
255 dpavlin 32 case ARCH_SH:
256     debug("useremul__netbsd_setup(): SH: TODO\n");
257     break;
258    
259 dpavlin 4 case ARCH_X86:
260     debug("useremul__netbsd_setup(): X86: TODO\n");
261    
262     break;
263    
264 dpavlin 2 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 dpavlin 12 stack_top - stacksize, stacksize, "userstack", 0, 0);
294 dpavlin 2
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 dpavlin 12 uint64_t baseaddr, uint64_t len)
373 dpavlin 2 {
374     unsigned char *charbuf;
375 dpavlin 22 size_t i;
376 dpavlin 2
377     charbuf = malloc(len);
378     if (charbuf == NULL) {
379     fprintf(stderr, "get_userland_buf(): out of memory (trying"
380 dpavlin 12 " to allocate %lli bytes)\n", (long long)len);
381 dpavlin 2 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 dpavlin 12 /*****************************************************************************/
414    
415    
416 dpavlin 2 /*
417 dpavlin 12 * 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 dpavlin 2 * useremul__freebsd():
654     *
655 dpavlin 12 * FreeBSD/Alpha syscall emulation.
656 dpavlin 2 *
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 dpavlin 12 int64_t res = 0, err = 0;
663     uint64_t arg0, arg1, arg2, arg3, arg4, arg5;
664 dpavlin 2
665 dpavlin 12 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 dpavlin 2
673 dpavlin 12 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 dpavlin 2 switch (nr) {
685    
686 dpavlin 12 case 1: res = useremul_exit(cpu, arg0);
687 dpavlin 2 break;
688    
689 dpavlin 12 case 4: res = useremul_write(cpu, &err, arg0, arg1, arg2);
690 dpavlin 2 break;
691    
692 dpavlin 12 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 dpavlin 22 case 73:/* munmap. TODO */
711     res = 1;
712     break;
713    
714 dpavlin 12 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 dpavlin 2 cpu->running = 0;
727     }
728 dpavlin 12
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 dpavlin 2 }
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 dpavlin 12 int64_t res = 0, err = 0;
750 dpavlin 2 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 dpavlin 12 res = useremul_exit(cpu, arg0);
767 dpavlin 2 break;
768    
769     case LINUX_PPC_SYS_write:
770 dpavlin 12 res = useremul_write(cpu, &err, arg0, arg1, arg2);
771 dpavlin 2 break;
772    
773     default:
774     fatal("useremul__linux(): syscall %i not yet implemented\n",
775     nr);
776     cpu->running = 0;
777     }
778 dpavlin 12
779     /* return res: TODO */
780 dpavlin 2 }
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 dpavlin 12 int64_t error_code = 0;
794 dpavlin 2 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 dpavlin 14
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 dpavlin 2 }
860    
861     /*
862 dpavlin 18 * NOTE/TODO: The following code should not be CPU arch dependent!
863 dpavlin 2 */
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 dpavlin 12 result_low = useremul_getuid(cpu);
956 dpavlin 2 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 dpavlin 12 useremul_break(cpu, arg0);
1014 dpavlin 2 break;
1015    
1016     case NETBSD_SYS_readlink:
1017 dpavlin 12 result_low = useremul_readlink(cpu, &error_code,
1018     arg0, arg1, arg2);
1019 dpavlin 2 break;
1020    
1021     case NETBSD_SYS_sync:
1022 dpavlin 12 useremul_sync(cpu);
1023 dpavlin 2 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 dpavlin 14 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 dpavlin 20 cpu->cd.arm.flags = cpu->cd.arm.cpsr >> 28;
1228 dpavlin 14 break;
1229 dpavlin 2 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 dpavlin 12 int64_t error_code = 0;
1271 dpavlin 2 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 dpavlin 12 useremul_break(cpu, arg0);
1392 dpavlin 2 break;
1393    
1394     case ULTRIX_SYS_sync:
1395 dpavlin 12 useremul_sync(cpu);
1396 dpavlin 2 break;
1397    
1398     case ULTRIX_SYS_getuid:
1399 dpavlin 12 result_low = useremul_getuid(cpu);
1400 dpavlin 2 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 dpavlin 12 result_low = useremul_fstat(cpu, &error_code, arg0, arg1);
1506 dpavlin 2 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 dpavlin 22 int iadd = DEBUG_INDENTATION * 2;
1728 dpavlin 2
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 dpavlin 32 add_useremul("NetBSD/sh", ARCH_SH, "SH4",
1766     useremul__netbsd, useremul__netbsd_setup);
1767    
1768 dpavlin 2 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 dpavlin 14 add_useremul("NetBSD/arm", ARCH_ARM, "SA1110",
1775 dpavlin 12 useremul__netbsd, useremul__netbsd_setup);
1776    
1777 dpavlin 4 add_useremul("NetBSD/amd64", ARCH_X86, "AMD64",
1778     useremul__netbsd, useremul__netbsd_setup);
1779    
1780 dpavlin 14 add_useremul("NetBSD/alpha", ARCH_ALPHA, "Alpha",
1781     useremul__netbsd, useremul__netbsd_setup);
1782    
1783 dpavlin 2 add_useremul("Linux/PPC64", ARCH_PPC, "PPC970",
1784     useremul__linux, useremul__linux_setup);
1785    
1786 dpavlin 12 add_useremul("FreeBSD/Alpha", ARCH_ALPHA, "Alpha",
1787 dpavlin 2 useremul__freebsd, useremul__freebsd_setup);
1788     }
1789    

  ViewVC Help
Powered by ViewVC 1.1.26