/[gxemul]/trunk/src/console.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 /trunk/src/console.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (hide annotations)
Mon Oct 8 16:19:56 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 24262 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1256 2006/06/23 20:43:44 debug Exp $
20060219	Various minor updates. Removing the old MIPS16 skeleton code,
		because it will need to be rewritten for dyntrans anyway.
20060220-22	Removing the non-working dyntrans backend support.
		Continuing on the 64-bit dyntrans virtual memory generalization.
20060223	More work on the 64-bit vm generalization.
20060225	Beginning on MIPS dyntrans load/store instructions.
		Minor PPC updates (64-bit load/store, etc).
		Fixes for the variable-instruction-length framework, some
		minor AVR updates (a simple Hello World program works!).
		Beginning on a skeleton for automatically generating documen-
		tation (for devices etc.).
20060226	PPC updates (adding some more 64-bit instructions, etc).
		AVR updates (more instructions).
		FINALLY found and fixed the zs bug, making NetBSD/macppc
		accept the serial console.
20060301	Adding more AVR instructions.
20060304	Continuing on AVR-related stuff. Beginning on a framework for
		cycle-accurate device emulation. Adding an experimental "PAL
		TV" device (just a dummy so far).
20060305	Adding more AVR instructions.
		Adding a dummy epcom serial controller (for TS7200 emulation).
20060310	Removing the emul() command from configuration files, so only
		net() and machine() are supported.
		Minor progress on the MIPS dyntrans rewrite.
20060311	Continuing on the MIPS dyntrans rewrite (adding more
		instructions, etc).
20060315	Adding more instructions (sllv, srav, srlv, bgtz[l], blez[l],
		beql, bnel, slti[u], various loads and stores).
20060316	Removing the ALWAYS_SIGNEXTEND_32 option, since it was rarely
		used.
		Adding more MIPS dyntrans instructions, and fixing bugs.
20060318	Implementing fast loads/stores for MIPS dyntrans (big/little
		endian, 32-bit and 64-bit modes).
20060320	Making MIPS dyntrans the default configure option; use
		"--enable-oldmips" to use the old bintrans system.
		Adding MIPS dyntrans dmult[u]; minor updates.
20060322	Continuing... adding some more instructions.
		Adding a simple skeleton for demangling C++ "_ZN" symbols.
20060323	Moving src/debugger.c into a new directory (src/debugger/).
20060324	Fixing the hack used to load PPC ELFs (useful for relocated
		Linux/ppc kernels), and adding a dummy G3 machine mode.
20060325-26	Beginning to experiment with GDB remote serial protocol
		connections; adding a -G command line option for selecting
		which TCP port to listen to.
20060330	Beginning a major cleanup to replace things like "0x%016llx"
		with more correct "0x%016"PRIx64, etc.
		Continuing on the GDB remote serial protocol support.
20060331	More cleanup, and some minor GDB remote progress.
20060402	Adding a hack to the configure script, to allow compilation
		on systems that lack PRIx64 etc.
20060406	Removing the temporary FreeBSD/arm hack in dev_ns16550.c and
		replacing it with a better fix from Olivier Houchard.
20060407	A remote debugger (gdb or ddd) can now start and stop the
		emulator using the GDB remote serial protocol, and registers
		and memory can be read. MIPS only for now.
20060408	More GDB progress: single-stepping also works, and also adding
		support for ARM, PowerPC, and Alpha targets.
		Continuing on the delay-slot-across-page-boundary issue.
20060412	Minor update: beginning to add support for the SPARC target
		to the remote GDB functionality.
20060414	Various MIPS updates: adding more instructions for dyntrans
		(eret, add), and making some exceptions work. Fixing a bug
		in dmult[u].
		Implementing the first SPARC instructions (sethi, or).
20060415	Adding "magic trap" instructions so that PROM calls can be
		software emulated in MIPS dyntrans.
		Adding more MIPS dyntrans instructions (ddiv, dadd) and
		fixing another bug in dmult.
20060416	More MIPS dyntrans progress: adding [d]addi, movn, movz, dsllv,
		rfi, an ugly hack for supporting R2000/R3000 style faked caches,
		preliminary interrupt support, and various other updates and
		bugfixes.
20060417	Adding more SPARC instructions (add, sub, sll[x], sra[x],
		srl[x]), and useful SPARC header definitions.
		Adding the first (trivial) x86/AMD64 dyntrans instructions (nop,
		cli/sti, stc/clc, std/cld, simple mov, inc ax). Various other
		x86 updates related to variable instruction length stuff.
		Adding unaligned loads/stores to the MIPS dyntrans mode (but
		still using the pre-dyntrans (slow) imlementation).
20060419	Fixing a MIPS dyntrans exception-in-delay-slot bug.
		Removing the old "show opcode statistics" functionality, since
		it wasn't really useful and isn't implemented for dyntrans.
		Single-stepping (or running with instruction trace) now looks
		ok with dyntrans with delay-slot architectures.
20060420	Minor hacks (removing the -B command line option when compiled
		for non-bintrans, and some other very minor updates).
		Adding (slow) MIPS dyntrans load-linked/store-conditional.
20060422	Applying fixes for bugs discovered by Nils Weller's nwcc
		(static DEC memmap => now per machine, and adding an extern
		keyword in cpu_arm_instr.c).
		Finally found one of the MIPS dyntrans bugs that I've been
		looking for (copy/paste spelling error BIG vs LITTLE endian in
		cpu_mips_instr_loadstore.c for 16-bit fast stores).
		FINALLY found the major MIPS dyntrans bug: slti vs sltiu
		signed/unsigned code in cpu_mips_instr.c. :-)
		Adding more MIPS dyntrans instructions (lwc1, swc1, bgezal[l],
		ctc1, tlt[u], tge[u], tne, beginning on rdhwr).
		NetBSD/hpcmips can now reach userland when using dyntrans :-)
		Adding some more x86 dyntrans instructions.
		Finally removed the old Alpha-specific virtual memory code,
		and replaced it with the generic 64-bit version.
		Beginning to add disassembly support for SPECIAL3 MIPS opcodes.
20060423	Continuing on the delay-slot-across-page-boundary issue;
		adding an end_of_page2 ic slot (like I had planned before, but
		had removed for some reason).
		Adding a quick-and-dirty fallback to legacy coprocessor 1
		code (i.e. skipping dyntrans implementation for now).
		NetBSD/hpcmips and NetBSD/pmax (when running on an emulated
		R4400) can now be installed and run. :-)  (Many bugs left
		to fix, though.)
		Adding more MIPS dyntrans instructions: madd[u], msub[u].
		Cleaning up the SPECIAL2 vs R5900/TX79/C790 "MMI" opcode
		maps somewhat (disassembly and dyntrans instruction decoding).
20060424	Adding an isa_revision field to mips_cpu_types.h, and making
		sure that SPECIAL3 opcodes cause Reserved Instruction
		exceptions on MIPS32/64 revisions lower than 2.
		Adding the SPARC 'ba', 'call', 'jmpl/retl', 'and', and 'xor'
		instructions.
20060425	Removing the -m command line option ("run at most x 
		instructions") and -T ("single_step_on_bad_addr"), because
		they never worked correctly with dyntrans anyway.
		Freshening up the man page.
20060428	Adding more MIPS dyntrans instructions: bltzal[l], idle.
		Enabling MIPS dyntrans compare interrupts.
20060429	FINALLY found the weird dyntrans bug, causing NetBSD etc. to
		behave strangely: some floating point code (conditional
		coprocessor branches) could not be reused from the old
		non-dyntrans code. The "quick-and-dirty fallback" only appeared
		to work. Fixing by implementing bc1* for MIPS dyntrans.
		More MIPS instructions: [d]sub, sdc1, ldc1, dmtc1, dmfc1, cfc0.
		Freshening up MIPS floating point disassembly appearance.
20060430	Continuing on C790/R5900/TX79 disassembly; implementing 128-bit
		"por" and "pextlw".
20060504	Disabling -u (userland emulation) unless compiled as unstable
		development version.
		Beginning on freshening up the testmachine include files,
		to make it easier to reuse those files (placing them in
		src/include/testmachine/), and beginning on a set of "demos"
		or "tutorials" for the testmachine functionality.
		Minor updates to the MIPS GDB remote protocol stub.
		Refreshing doc/experiments.html and gdb_remote.html.
		Enabling Alpha emulation in the stable release configuration,
		even though no guest OSes for Alpha can run yet.
20060505	Adding a generic 'settings' object, which will contain
		references to settable variables (which will later be possible
		to access using the debugger).
20060506	Updating dev_disk and corresponding demo/documentation (and
		switching from SCSI to IDE disk types, so it actually works
		with current test machines :-).
20060510	Adding a -D_LARGEFILE_SOURCE hack for 64-bit Linux hosts,
		so that fseeko() doesn't give a warning.
		Updating the section about how dyntrans works (the "runnable
		IR") in doc/intro.html.
		Instruction updates (some x64=1 checks, some more R5900
		dyntrans stuff: better mul/mult separation from MIPS32/64,
		adding ei and di).
		Updating MIPS cpuregs.h to a newer one (from NetBSD).
		Adding more MIPS dyntrans instructions: deret, ehb.
20060514	Adding disassembly and beginning implementation of SPARC wr
		and wrpr instructions.
20060515	Adding a SUN SPARC machine mode, with dummy SS20 and Ultra1
		machines. Adding the 32-bit "rd psr" instruction.
20060517	Disassembly support for the general SPARC rd instruction.
		Partial implementation of the cmp (subcc) instruction.
		Some other minor updates (making sure that R5900 processors
		start up with the EIE bit enabled, otherwise Linux/playstation2
		receives no interrupts).
20060519	Minor MIPS updates/cleanups.
20060521	Moving the MeshCube machine into evbmips; this seems to work
		reasonably well with a snapshot of a NetBSD MeshCube kernel.
		Cleanup/fix of MIPS config0 register initialization.
20060529	Minor MIPS fixes, including a sign-extension fix to the
		unaligned load/store code, which makes NetBSD/pmax on R3000
		work better with dyntrans. (Ultrix and Linux/DECstation still
		don't work, though.)
20060530	Minor updates to the Alpha machine mode: adding an AlphaBook
		mode, an LCA bus (forwarding accesses to an ISA bus), etc.
20060531	Applying a bugfix for the MIPS dyntrans sc[d] instruction from
		Ondrej Palkovsky. (Many thanks.)
20060601	Minifix to allow ARM immediate msr instruction to not give
		an error for some valid values.
		More Alpha updates.
20060602	Some minor Alpha updates.
20060603	Adding the Alpha cmpbge instruction. NetBSD/alpha prints its
		first boot messages :-) on an emulated Alphabook 1.
20060612	Minor updates; adding a dev_ether.h include file for the
		testmachine ether device. Continuing the hunt for the dyntrans
		bug which makes Linux and Ultrix on DECstation behave
		strangely... FINALLY found it! It seems to be related to
		invalidation of the translation cache, on tlbw{r,i}. There
		also seems to be some remaining interrupt-related problems.
20060614	Correcting the implementation of ldc1/sdc1 for MIPS dyntrans
		(so that it uses 16 32-bit registers if the FR bit in the
		status register is not set).
20060616	REMOVING BINTRANS COMPLETELY!
		Removing the old MIPS interpretation mode.
		Removing the MFHILO_DELAY and instruction delay stuff, because
		they wouldn't work with dyntrans anyway.
20060617	Some documentation updates (adding "NetBSD-archive" to some
		URLs, and new Debian/DECstation installation screenshots).
		Removing the "tracenull" and "enable-caches" configure options.
		Improving MIPS dyntrans performance somewhat (only invalidate
		translations if necessary, on writes to the entryhi register,
		instead of doing it for all cop0 writes).
20060618	More cleanup after the removal of the old MIPS emulation.
		Trying to fix the MIPS dyntrans performance bugs/bottlenecks;
		only semi-successful so far (for R3000).
20060620	Minor update to allow clean compilation again on Tru64/Alpha.
20060622	MIPS cleanup and fixes (removing the pc_last stuff, which
		doesn't make sense with dyntrans anyway, and fixing a cross-
		page-delay-slot-with-exception case in end_of_page).
		Removing the old max_random_cycles_per_chunk stuff, and the
		concept of cycles vs instructions for MIPS emulation.
		FINALLY found and fixed the bug which caused NetBSD/pmax
		clocks to behave strangely (it was a load to the zero register,
		which was treated as a NOP; now it is treated as a load to a
		dummy scratch register).
20060623	Increasing the dyntrans chunk size back to
		N_SAFE_DYNTRANS_LIMIT, instead of N_SAFE_DYNTRANS_LIMIT/2.
		Preparing for a quick release, even though there are known
		bugs, and performance for non-R3000 MIPS emulation is very
		poor. :-/
		Reverting to half the dyntrans chunk size again, because
		NetBSD/cats seemed less stable with full size chunks. :(
		NetBSD/sgimips 3.0 can now run :-)  (With release 0.3.8, only
		NetBSD/sgimips 2.1 worked, not 3.0.)

==============  RELEASE 0.4.0  ==============


1 dpavlin 2 /*
2 dpavlin 22 * Copyright (C) 2003-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 24 * $Id: console.c,v 1.16 2006/05/05 21:28:09 debug Exp $
29 dpavlin 2 *
30     * Generic console support functions.
31     *
32 dpavlin 22 * This module is used by individual device drivers, for example serial
33     * controllers, keyboards, or other devices which need to attach to the
34     * emulator's real stdin/stdout.
35 dpavlin 2 *
36 dpavlin 22 * The idea is that several input and output streams (console handles) are
37     * allowed. As long as the number of input streams is <= 1, then everything
38     * can be done in the emulator's default terminal window.
39     *
40     * If the number of inputs is more than 1, it is necessary to open up slave
41     * xterm windows for each input. (Otherwise the behaviour is undefined; i.e.
42     * which of two emulated serial controllers would get keyboard input?)
43     *
44     * (If the -x command line option is NOT used, then slaves are not opened up.
45     * Instead, a warning message is printed, and input is not allowed.)
46     *
47     * Note that console handles that _allow_ input but are not yet used for
48     * output are not counted. This allows a machine to have, say, 2 serial ports
49     * which can be used for both input and output, and it will still be possible
50     * to run in the default terminal window as long as only one of those serial
51     * ports is actually used.
52     *
53     * xterms are opened up "on demand", when output is sent to them.
54     *
55     * The MAIN console handle (fixed as handle nr 0) is the one used by the
56     * default terminal window. A machine which registers a serial controller,
57     * which should be used as the main way of communicating with guest operating
58     * systems running on that machine, should set machine->main_console_handle
59     * to the handle of the correct port on that controller.
60     *
61     *
62     * NOTE: The code in this module is mostly non-reentrant.
63 dpavlin 2 */
64    
65     #include <errno.h>
66     #include <signal.h>
67     #include <stdio.h>
68     #include <stdlib.h>
69     #include <string.h>
70     #include <termios.h>
71     #include <unistd.h>
72     #include <sys/types.h>
73    
74     #include "console.h"
75     #include "emul.h"
76     #include "machine.h"
77     #include "memory.h"
78     #include "misc.h"
79 dpavlin 24 #include "settings.h"
80 dpavlin 2
81    
82     extern char *progname;
83 dpavlin 22 extern int verbose;
84 dpavlin 24 extern struct settings *global_settings;
85 dpavlin 2
86    
87     static struct termios console_oldtermios;
88     static struct termios console_curtermios;
89    
90     /* For 'slave' mode: */
91     static struct termios console_slave_tios;
92     static int console_slave_outputd;
93    
94     static int console_initialized = 0;
95     static int console_stdout_pending;
96    
97     #define CONSOLE_FIFO_LEN 4096
98    
99     /* Mouse coordinates: */
100     static int console_framebuffer_mouse_x; /* absolute x, 0-based */
101     static int console_framebuffer_mouse_y; /* absolute y, 0-based */
102     static int console_framebuffer_mouse_fb_nr; /* fb_number of last
103     framebuffer cursor update */
104    
105     static int console_mouse_x; /* absolute x, 0-based */
106     static int console_mouse_y; /* absolute y, 0-based */
107     static int console_mouse_fb_nr; /* framebuffer number of
108     host movement, 0-based */
109     static int console_mouse_buttons; /* left=4, middle=2, right=1 */
110    
111     static int allow_slaves = 0;
112    
113     struct console_handle {
114     int in_use;
115 dpavlin 22 int in_use_for_input;
116 dpavlin 2 int using_xterm;
117     int inputonly;
118 dpavlin 22 int outputonly;
119     int warning_printed;
120 dpavlin 2
121 dpavlin 22 char *machine_name;
122 dpavlin 2 char *name;
123    
124     int w_descriptor;
125     int r_descriptor;
126    
127     unsigned char fifo[CONSOLE_FIFO_LEN];
128     int fifo_head;
129     int fifo_tail;
130     };
131    
132     #define NOT_USING_XTERM 0
133     #define USING_XTERM_BUT_NOT_YET_OPEN 1
134     #define USING_XTERM 2
135    
136     /* A simple array of console_handles */
137     static struct console_handle *console_handles = NULL;
138     static int n_console_handles = 0;
139    
140    
141     /*
142     * console_deinit():
143     *
144     * Restore host's console settings.
145     */
146     void console_deinit(void)
147     {
148     if (!console_initialized)
149     return;
150    
151     tcsetattr(STDIN_FILENO, TCSANOW, &console_oldtermios);
152    
153     console_initialized = 0;
154     }
155    
156    
157     /*
158     * console_sigcont():
159     *
160     * If the user presses CTRL-Z (to stop the emulator process) and then
161     * continues, we have to make sure that the right termios settings are
162     * active. (This should be set as the SIGCONT signal handler in src/emul.c.)
163     */
164     void console_sigcont(int x)
165     {
166     if (!console_initialized)
167     return;
168    
169     /* Make sure our 'current' termios setting is active: */
170     tcsetattr(STDIN_FILENO, TCSANOW, &console_curtermios);
171    
172     /* Reset the signal handler: */
173     signal(SIGCONT, console_sigcont);
174     }
175    
176    
177     /*
178     * start_xterm():
179     *
180 dpavlin 22 * When using X11 (well, when allow_slaves is set), this routine tries to
181     * start up an xterm, with another copy of gxemul inside. The other gxemul
182     * copy is given arguments that will cause it to run console_slave().
183     *
184     * TODO: This is ugly and hardcoded. Clean it up.
185 dpavlin 2 */
186     static void start_xterm(int handle)
187     {
188     int filedes[2];
189     int filedesB[2];
190     int res;
191 dpavlin 22 size_t mlen;
192 dpavlin 2 char **a;
193     pid_t p;
194    
195     res = pipe(filedes);
196     if (res) {
197     printf("[ start_xterm(): pipe(): %i ]\n", errno);
198     exit(1);
199     }
200    
201     res = pipe(filedesB);
202     if (res) {
203     printf("[ start_xterm(): pipe(): %i ]\n", errno);
204     exit(1);
205     }
206    
207     /* printf("filedes = %i,%i\n", filedes[0], filedes[1]); */
208     /* printf("filedesB = %i,%i\n", filedesB[0], filedesB[1]); */
209    
210     /* NOTE/warning: Hardcoded max nr of args! */
211     a = malloc(sizeof(char *) * 20);
212     if (a == NULL) {
213 dpavlin 22 fprintf(stderr, "start_xterm(): out of memory\n");
214 dpavlin 2 exit(1);
215     }
216    
217     a[0] = getenv("XTERM");
218     if (a[0] == NULL)
219     a[0] = "xterm";
220 dpavlin 6 a[1] = "-geometry";
221     a[2] = "80x25";
222     a[3] = "-title";
223 dpavlin 22 mlen = strlen(console_handles[handle].name) +
224     strlen(console_handles[handle].machine_name) + 30;
225     a[4] = malloc(mlen);
226     snprintf(a[4], mlen, "GXemul: %s %s",
227     console_handles[handle].machine_name,
228     console_handles[handle].name);
229 dpavlin 6 a[5] = "-e";
230     a[6] = progname;
231 dpavlin 10 a[7] = malloc(80);
232     snprintf(a[7], 80, "-WW@S%i,%i", filedes[0], filedesB[1]);
233 dpavlin 6 a[8] = NULL;
234 dpavlin 2
235     p = fork();
236     if (p == -1) {
237 dpavlin 22 printf("[ start_xterm(): ERROR while trying to "
238 dpavlin 2 "fork(): %i ]\n", errno);
239     exit(1);
240     } else if (p == 0) {
241     close(filedes[1]);
242     close(filedesB[0]);
243    
244     p = setsid();
245     if (p < 0)
246 dpavlin 22 printf("[ start_xterm(): ERROR while trying "
247 dpavlin 2 "to do a setsid(): %i ]\n", errno);
248    
249     res = execvp(a[0], a);
250 dpavlin 22 printf("[ start_xterm(): ERROR while trying to "
251 dpavlin 2 "execvp(\"");
252     while (a[0] != NULL) {
253     printf("%s", a[0]);
254     if (a[1] != NULL)
255     printf(" ");
256     a++;
257     }
258     printf("\"): %i ]\n", errno);
259 dpavlin 22 if (errno == ENOENT)
260     printf("[ Most probably you don't have xterm"
261     " in your PATH. Try again. ]\n");
262 dpavlin 2 exit(1);
263     }
264    
265     /* TODO: free a and a[*] */
266    
267     close(filedes[0]);
268     close(filedesB[1]);
269    
270     console_handles[handle].using_xterm = USING_XTERM;
271    
272     /*
273     * write to filedes[1], read from filedesB[0]
274     */
275    
276     console_handles[handle].w_descriptor = filedes[1];
277     console_handles[handle].r_descriptor = filedesB[0];
278     }
279    
280    
281     /*
282     * d_avail():
283     *
284     * Returns 1 if anything is available on a descriptor.
285     */
286     static int d_avail(int d)
287     {
288     fd_set rfds;
289     struct timeval tv;
290    
291     FD_ZERO(&rfds);
292     FD_SET(d, &rfds);
293     tv.tv_sec = 0;
294     tv.tv_usec = 0;
295     return select(d+1, &rfds, NULL, NULL, &tv);
296     }
297    
298    
299     /*
300     * console_makeavail():
301     *
302     * Put a character in the queue, so that it will be avaiable,
303     * by inserting it into the char fifo.
304     */
305     void console_makeavail(int handle, char ch)
306     {
307     console_handles[handle].fifo[
308     console_handles[handle].fifo_head] = ch;
309     console_handles[handle].fifo_head = (
310     console_handles[handle].fifo_head + 1) % CONSOLE_FIFO_LEN;
311    
312     if (console_handles[handle].fifo_head ==
313     console_handles[handle].fifo_tail)
314     fatal("[ WARNING: console fifo overrun, handle %i ]\n", handle);
315     }
316    
317    
318     /*
319     * console_stdin_avail():
320     *
321     * Returns 1 if a char is available from a handle's read descriptor,
322     * 0 otherwise.
323     */
324     static int console_stdin_avail(int handle)
325     {
326 dpavlin 22 if (!console_handles[handle].in_use_for_input)
327     return 0;
328    
329 dpavlin 2 if (!allow_slaves)
330     return d_avail(STDIN_FILENO);
331    
332     if (console_handles[handle].using_xterm ==
333     USING_XTERM_BUT_NOT_YET_OPEN)
334     return 0;
335    
336     return d_avail(console_handles[handle].r_descriptor);
337     }
338    
339    
340     /*
341     * console_charavail():
342     *
343     * Returns 1 if a char is available in the fifo, 0 otherwise.
344     */
345     int console_charavail(int handle)
346     {
347     while (console_stdin_avail(handle)) {
348     unsigned char ch[100]; /* = getchar(); */
349     ssize_t len;
350     int i, d;
351    
352     if (!allow_slaves)
353     d = STDIN_FILENO;
354     else
355     d = console_handles[handle].r_descriptor;
356    
357     len = read(d, ch, sizeof(ch));
358    
359     for (i=0; i<len; i++) {
360     /* printf("[ %i: %i ]\n", i, ch[i]); */
361    
362     if (!allow_slaves) {
363     /* Ugly hack: convert ctrl-b into ctrl-c.
364     (TODO: fix) */
365     if (ch[i] == 2)
366     ch[i] = 3;
367     }
368    
369     console_makeavail(handle, ch[i]);
370     }
371     }
372    
373     if (console_handles[handle].fifo_head ==
374     console_handles[handle].fifo_tail)
375     return 0;
376    
377     return 1;
378     }
379    
380    
381     /*
382     * console_readchar():
383     *
384     * Returns 0..255 if a char was available, -1 otherwise.
385     */
386     int console_readchar(int handle)
387     {
388     int ch;
389    
390     if (!console_charavail(handle))
391     return -1;
392    
393     ch = console_handles[handle].fifo[console_handles[handle].fifo_tail];
394     console_handles[handle].fifo_tail ++;
395     console_handles[handle].fifo_tail %= CONSOLE_FIFO_LEN;
396    
397     return ch;
398     }
399    
400    
401     /*
402     * console_putchar():
403     *
404     * Prints a char to stdout, and sets the console_stdout_pending flag.
405     */
406     void console_putchar(int handle, int ch)
407     {
408     char buf[1];
409    
410 dpavlin 22 if (!console_handles[handle].in_use_for_input &&
411     !console_handles[handle].outputonly)
412     console_change_inputability(handle, 1);
413    
414 dpavlin 2 if (!allow_slaves) {
415     /* stdout: */
416     putchar(ch);
417    
418     /* Assume flushes by OS or libc on newlines: */
419     if (ch == '\n')
420     console_stdout_pending = 0;
421     else
422     console_stdout_pending = 1;
423    
424     return;
425     }
426    
427     if (!console_handles[handle].in_use) {
428     printf("[ console_putchar(): handle %i not in"
429     " use! ]\n", handle);
430     return;
431     }
432    
433     if (console_handles[handle].using_xterm ==
434     USING_XTERM_BUT_NOT_YET_OPEN)
435     start_xterm(handle);
436    
437     buf[0] = ch;
438     write(console_handles[handle].w_descriptor, buf, 1);
439     }
440    
441    
442     /*
443     * console_flush():
444     *
445     * Flushes stdout, if necessary, and resets console_stdout_pending to zero.
446     */
447     void console_flush(void)
448     {
449     if (console_stdout_pending)
450     fflush(stdout);
451    
452     console_stdout_pending = 0;
453     }
454    
455    
456     /*
457     * console_mouse_coordinates():
458     *
459     * Sets mouse coordinates. Called by for example an X11 event handler.
460     * x and y are absolute coordinates, fb_nr is where the mouse movement
461     * took place.
462     */
463     void console_mouse_coordinates(int x, int y, int fb_nr)
464     {
465     /* TODO: fb_nr isn't used yet. */
466    
467     console_mouse_x = x;
468     console_mouse_y = y;
469     console_mouse_fb_nr = fb_nr;
470     }
471    
472    
473     /*
474     * console_mouse_button():
475     *
476     * Sets a mouse button to be pressed or released. Called by for example an
477     * X11 event handler. button is 1 (left), 2 (middle), or 3 (right), and
478     * pressed = 1 for pressed, 0 for not pressed.
479     */
480     void console_mouse_button(int button, int pressed)
481     {
482     int mask = 1 << (3-button);
483    
484     if (pressed)
485     console_mouse_buttons |= mask;
486     else
487     console_mouse_buttons &= ~mask;
488     }
489    
490    
491     /*
492     * console_get_framebuffer_mouse():
493     *
494     * TODO: Comment
495     */
496     void console_get_framebuffer_mouse(int *x, int *y, int *fb_nr)
497     {
498     *x = console_framebuffer_mouse_x;
499     *y = console_framebuffer_mouse_y;
500     *fb_nr = console_framebuffer_mouse_fb_nr;
501     }
502    
503    
504     /*
505     * console_set_framebuffer_mouse():
506     *
507     * A framebuffer device calls this function when it sets the
508     * position of a cursor (ie a mouse cursor).
509     */
510     void console_set_framebuffer_mouse(int x, int y, int fb_nr)
511     {
512     console_framebuffer_mouse_x = x;
513     console_framebuffer_mouse_y = y;
514     console_framebuffer_mouse_fb_nr = fb_nr;
515     }
516    
517    
518     /*
519     * console_getmouse():
520     *
521     * Puts current mouse data into the variables pointed to by
522     * the arguments.
523     */
524     void console_getmouse(int *x, int *y, int *buttons, int *fb_nr)
525     {
526     *x = console_mouse_x;
527     *y = console_mouse_y;
528     *buttons = console_mouse_buttons;
529     *fb_nr = console_mouse_fb_nr;
530     }
531    
532    
533     /*
534     * console_slave_sigint():
535     */
536     static void console_slave_sigint(int x)
537     {
538     char buf[1];
539    
540     /* Send a ctrl-c: */
541     buf[0] = 3;
542     write(console_slave_outputd, buf, sizeof(buf));
543    
544     /* Reset the signal handler: */
545     signal(SIGINT, console_slave_sigint);
546     }
547    
548    
549     /*
550     * console_slave_sigcont():
551     *
552     * See comment for console_sigcont. This is for used by console_slave().
553     */
554     static void console_slave_sigcont(int x)
555     {
556     /* Make sure our 'current' termios setting is active: */
557     tcsetattr(STDIN_FILENO, TCSANOW, &console_slave_tios);
558    
559     /* Reset the signal handler: */
560     signal(SIGCONT, console_slave_sigcont);
561     }
562    
563    
564     /*
565     * console_slave():
566     *
567     * This function is used when running with X11, and gxemul opens up
568     * separate xterms for each emulated terminal or serial port.
569     */
570     void console_slave(char *arg)
571     {
572     int inputd;
573     int len;
574     char *p;
575     char buf[400];
576    
577     /* arg = '3,6' or similar, input and output descriptors */
578     /* printf("console_slave(): arg = '%s'\n", arg); */
579    
580     inputd = atoi(arg);
581     p = strchr(arg, ',');
582     if (p == NULL) {
583     printf("console_slave(): bad arg '%s'\n", arg);
584     sleep(5);
585     exit(1);
586     }
587     console_slave_outputd = atoi(p+1);
588    
589     /* Set the terminal to raw mode: */
590     tcgetattr(STDIN_FILENO, &console_slave_tios);
591    
592     console_slave_tios.c_lflag &= ~ICANON;
593     console_slave_tios.c_cc[VTIME] = 0;
594     console_slave_tios.c_cc[VMIN] = 1;
595     console_slave_tios.c_lflag &= ~ECHO;
596     console_slave_tios.c_iflag &= ~ICRNL;
597     tcsetattr(STDIN_FILENO, TCSANOW, &console_slave_tios);
598    
599     signal(SIGINT, console_slave_sigint);
600     signal(SIGCONT, console_slave_sigcont);
601    
602     for (;;) {
603     /* TODO: select() on both inputd and stdin */
604    
605     if (d_avail(inputd)) {
606     len = read(inputd, buf, sizeof(buf) - 1);
607     if (len < 1)
608     exit(0);
609     buf[len] = '\0';
610     printf("%s", buf);
611     fflush(stdout);
612     }
613    
614     if (d_avail(STDIN_FILENO)) {
615     len = read(STDIN_FILENO, buf, sizeof(buf));
616     if (len < 1)
617     exit(0);
618     write(console_slave_outputd, buf, len);
619     }
620    
621     usleep(100);
622     }
623     }
624    
625    
626     /*
627     * console_new_handle():
628     *
629     * Allocates a new console_handle struct, and returns a pointer to it.
630     *
631     * For internal use.
632     */
633     static struct console_handle *console_new_handle(char *name, int *handlep)
634     {
635     struct console_handle *chp;
636     int i, n, found_free = -1;
637    
638     /* Reuse an old slot, if possible: */
639     n = n_console_handles;
640     for (i=0; i<n; i++)
641     if (!console_handles[i].in_use) {
642     found_free = i;
643     break;
644     }
645    
646     if (found_free == -1) {
647     /* Let's realloc console_handles[], to make room
648     for the new one: */
649     console_handles = realloc(console_handles, sizeof(
650     struct console_handle) * (n_console_handles + 1));
651     if (console_handles == NULL) {
652     printf("console_new_handle(): out of memory\n");
653     exit(1);
654     }
655     found_free = n_console_handles;
656     n_console_handles ++;
657     }
658    
659     chp = &console_handles[found_free];
660     memset(chp, 0, sizeof(struct console_handle));
661    
662     chp->in_use = 1;
663 dpavlin 22 chp->machine_name = "";
664 dpavlin 2 chp->name = strdup(name);
665     if (chp->name == NULL) {
666     printf("console_new_handle(): out of memory\n");
667     exit(1);
668     }
669    
670     *handlep = found_free;
671     return chp;
672     }
673    
674    
675     /*
676     * console_start_slave():
677     *
678     * When using X11:
679     *
680     * This routine tries to start up an xterm, with another copy of gxemul
681     * inside. The other gxemul copy is given arguments that will cause it
682     * to run console_slave().
683     *
684     * When not using X11: Things will seem to work the same way without X11,
685     * but no xterm will actually be started.
686     *
687     * consolename should be something like "serial 0".
688     *
689 dpavlin 22 * If use_for_input is 1, input is allowed right from the start. (This
690     * can be upgraded later from 0 to 1 using the console_change_inputability()
691     * function.)
692     *
693     * If use_for_input is CONSOLE_OUTPUT_ONLY, then this is an output-only stream.
694     *
695 dpavlin 2 * On success, an integer >= 0 is returned. This can then be used as a
696     * 'handle' when writing to or reading from an emulated console.
697     *
698     * On failure, -1 is returned.
699     */
700 dpavlin 22 int console_start_slave(struct machine *machine, char *consolename,
701     int use_for_input)
702 dpavlin 2 {
703 dpavlin 22 struct console_handle *chp;
704 dpavlin 2 int handle;
705    
706     if (machine == NULL || consolename == NULL) {
707     printf("console_start_slave(): NULL ptr\n");
708     exit(1);
709     }
710    
711     chp = console_new_handle(consolename, &handle);
712 dpavlin 22 chp->in_use_for_input = use_for_input;
713     if (use_for_input == CONSOLE_OUTPUT_ONLY) {
714     chp->outputonly = 1;
715     chp->in_use_for_input = 0;
716 dpavlin 2 }
717 dpavlin 22 chp->machine_name = strdup(machine->machine_name);
718     chp->name = strdup(consolename);
719 dpavlin 2
720 dpavlin 22 if (allow_slaves)
721     chp->using_xterm = USING_XTERM_BUT_NOT_YET_OPEN;
722 dpavlin 2
723     return handle;
724     }
725    
726    
727     /*
728     * console_start_slave_inputonly():
729     *
730     * Similar to console_start_slave(), but doesn't open an xterm. This is
731     * useful for devices such as keyboard controllers, that need to have an
732     * input queue, but no xterm window associated with it.
733     *
734     * On success, an integer >= 0 is returned. This can then be used as a
735     * 'handle' when writing to or reading from an emulated console.
736     *
737     * On failure, -1 is returned.
738     */
739 dpavlin 22 int console_start_slave_inputonly(struct machine *machine, char *consolename,
740     int use_for_input)
741 dpavlin 2 {
742     struct console_handle *chp;
743     int handle;
744    
745     if (machine == NULL || consolename == NULL) {
746     printf("console_start_slave(): NULL ptr\n");
747     exit(1);
748     }
749    
750     chp = console_new_handle(consolename, &handle);
751     chp->inputonly = 1;
752 dpavlin 22 chp->in_use_for_input = use_for_input;
753     chp->machine_name = strdup(machine->name);
754     chp->name = strdup(consolename);
755 dpavlin 2
756 dpavlin 22 return handle;
757     }
758    
759    
760     /*
761     * console_change_inputability():
762     *
763     * Sets whether or not a console handle can be used for input. Return value
764     * is 1 if the change took place, 0 otherwise.
765     */
766     int console_change_inputability(int handle, int inputability)
767     {
768     int old;
769    
770     if (handle < 0 || handle >= n_console_handles) {
771     fatal("console_change_inputability(): bad handle %i\n",
772     handle);
773 dpavlin 2 exit(1);
774     }
775    
776 dpavlin 22 old = console_handles[handle].in_use_for_input;
777     console_handles[handle].in_use_for_input = inputability;
778    
779     if (inputability != 0) {
780     if (console_warn_if_slaves_are_needed(0)) {
781     console_handles[handle].in_use_for_input = old;
782     if (!console_handles[handle].warning_printed) {
783     fatal("%%\n%% WARNING! Input to console ha"
784     "ndle \"%s\" wasn't enabled,\n%% because "
785     "it", console_handles[handle].name);
786     fatal(" would interfere with other inputs,\n"
787     "%% and you did not use the -x command "
788     "line option!\n%%\n");
789     }
790     console_handles[handle].warning_printed = 1;
791     return 0;
792     }
793     }
794    
795     return 1;
796 dpavlin 2 }
797    
798    
799     /*
800     * console_init_main():
801     *
802 dpavlin 22 * Puts the host's console into single-character (non-canonical) mode.
803 dpavlin 2 */
804     void console_init_main(struct emul *emul)
805     {
806     int i, tra;
807    
808     if (console_initialized)
809     return;
810    
811     tcgetattr(STDIN_FILENO, &console_oldtermios);
812     memcpy(&console_curtermios, &console_oldtermios,
813     sizeof (struct termios));
814    
815     console_curtermios.c_lflag &= ~ICANON;
816     console_curtermios.c_cc[VTIME] = 0;
817     console_curtermios.c_cc[VMIN] = 1;
818    
819     console_curtermios.c_lflag &= ~ECHO;
820    
821     /*
822     * Most guest OSes seem to work ok without ~ICRNL, but Linux on
823     * DECstation requires it to be usable. Unfortunately, clearing
824     * out ICRNL makes tracing with '-t ... |more' akward, as you
825     * might need to use CTRL-J instead of the enter key. Hence,
826     * this bit is only cleared if we're not tracing:
827     */
828     tra = 0;
829     for (i=0; i<emul->n_machines; i++)
830     if (emul->machines[i]->show_trace_tree ||
831     emul->machines[i]->instruction_trace ||
832     emul->machines[i]->register_dump)
833     tra = 1;
834     if (!tra)
835     console_curtermios.c_iflag &= ~ICRNL;
836    
837     tcsetattr(STDIN_FILENO, TCSANOW, &console_curtermios);
838    
839     console_stdout_pending = 1;
840     console_handles[MAIN_CONSOLE].fifo_head = 0;
841     console_handles[MAIN_CONSOLE].fifo_tail = 0;
842    
843     console_mouse_x = 0;
844     console_mouse_y = 0;
845     console_mouse_buttons = 0;
846    
847     console_initialized = 1;
848     }
849    
850    
851     /*
852 dpavlin 22 * console_debug_dump():
853     *
854     * Dump debug info, if verbose >= 2.
855     */
856     void console_debug_dump(struct machine *machine)
857     {
858     int i, iadd = DEBUG_INDENTATION, listed_main = 0;
859    
860     if (verbose < 2)
861     return;
862    
863     debug("console slaves (xterms): %s\n", allow_slaves?
864     "yes" : "no");
865    
866     debug("console handles:\n");
867     debug_indentation(iadd);
868    
869     for (i=0; i<n_console_handles; i++) {
870     if (!console_handles[i].in_use)
871     continue;
872     debug("%i: \"%s\"", i, console_handles[i].name);
873     if (console_handles[i].using_xterm)
874     debug(" [xterm]");
875     if (console_handles[i].inputonly)
876     debug(" [inputonly]");
877     if (console_handles[i].outputonly)
878     debug(" [outputonly]");
879     if (i == machine->main_console_handle) {
880     debug(" [MAIN CONSOLE]");
881     listed_main = 1;
882     }
883     debug("\n");
884     }
885    
886     debug_indentation(-iadd);
887    
888     if (!listed_main)
889     fatal("WARNING! no main console handle?\n");
890     }
891    
892    
893     /*
894 dpavlin 2 * console_allow_slaves():
895     *
896     * This function tells the console subsystem whether or not to open up
897     * slave xterms for each emulated serial controller.
898     */
899     void console_allow_slaves(int allow)
900     {
901     allow_slaves = allow;
902     }
903    
904    
905     /*
906 dpavlin 20 * console_are_slaves_allowed():
907     *
908     * Returns the value of allow_slaves.
909     */
910     int console_are_slaves_allowed(void)
911     {
912     return allow_slaves;
913     }
914    
915    
916     /*
917     * console_warn_if_slaves_are_needed():
918     *
919 dpavlin 22 * Prints an error (during startup of the emulator) if slave xterms are needed
920     * (i.e. there is more than one console handle in use which is used for
921     * INPUT), but they are not currently allowed.
922     *
923     * This function should be called during startup (with init = 1), and every
924     * time a console handle changes/upgrades its in_use_for_input from 0 to 1.
925     *
926     * If init is non-zero, this function doesn't return if there was a warning.
927     *
928     * If init is zero, no warning is printed. 1 is returned if there were more
929     * than one input, 0 otherwise.
930 dpavlin 20 */
931 dpavlin 22 int console_warn_if_slaves_are_needed(int init)
932 dpavlin 20 {
933     int i, n = 0;
934 dpavlin 22
935     if (allow_slaves)
936     return 0;
937    
938 dpavlin 20 for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
939     if (console_handles[i].in_use &&
940 dpavlin 22 console_handles[i].in_use_for_input &&
941 dpavlin 20 !console_handles[i].using_xterm)
942     n ++;
943    
944 dpavlin 22 if (n > 1) {
945     if (init) {
946     fatal("#\n# ERROR! More than one console input is "
947     "in use,\n# but xterm slaves are not enabled.\n"
948     "#\n");
949     fatal("# Use -x to enable slave xterms.)\n#\n");
950     for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
951     if (console_handles[i].in_use &&
952     console_handles[i].in_use_for_input &&
953     !console_handles[i].using_xterm)
954     fatal("# console handle %i: '%s'\n",
955     i, console_handles[i].name);
956     fatal("#\n");
957     exit(1);
958     }
959     return 1;
960 dpavlin 20 }
961 dpavlin 22
962     return 0;
963 dpavlin 20 }
964    
965    
966     /*
967 dpavlin 2 * console_init():
968     *
969     * This function should be called before any other console_*() function
970     * is used.
971     */
972     void console_init(void)
973     {
974     int handle;
975     struct console_handle *chp;
976 dpavlin 24 struct settings *console_settings = settings_new();
977 dpavlin 2
978 dpavlin 24 settings_add(global_settings, "console", 1,
979     SETTINGS_TYPE_SUBSETTINGS, 0, console_settings);
980    
981     settings_add(console_settings, "allow_slaves", 0,
982     SETTINGS_TYPE_INT, SETTINGS_FORMAT_YESNO, (void *)&allow_slaves);
983    
984 dpavlin 2 chp = console_new_handle("MAIN", &handle);
985     if (handle != MAIN_CONSOLE) {
986     printf("console_init(): fatal error: could not create"
987     " console 0: handle = %i\n", handle);
988     exit(1);
989     }
990 dpavlin 22
991     chp->in_use_for_input = 1;
992 dpavlin 2 }
993    

  ViewVC Help
Powered by ViewVC 1.1.26