/[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

Contents of /trunk/src/console.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 24 - (show annotations)
Mon Oct 8 16:19:56 2007 UTC (13 years, 1 month 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 /*
2 * Copyright (C) 2003-2006 Anders Gavare. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * 3. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 *
28 * $Id: console.c,v 1.16 2006/05/05 21:28:09 debug Exp $
29 *
30 * Generic console support functions.
31 *
32 * 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 *
36 * 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 */
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 #include "settings.h"
80
81
82 extern char *progname;
83 extern int verbose;
84 extern struct settings *global_settings;
85
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 int in_use_for_input;
116 int using_xterm;
117 int inputonly;
118 int outputonly;
119 int warning_printed;
120
121 char *machine_name;
122 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 * 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 */
186 static void start_xterm(int handle)
187 {
188 int filedes[2];
189 int filedesB[2];
190 int res;
191 size_t mlen;
192 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 fprintf(stderr, "start_xterm(): out of memory\n");
214 exit(1);
215 }
216
217 a[0] = getenv("XTERM");
218 if (a[0] == NULL)
219 a[0] = "xterm";
220 a[1] = "-geometry";
221 a[2] = "80x25";
222 a[3] = "-title";
223 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 a[5] = "-e";
230 a[6] = progname;
231 a[7] = malloc(80);
232 snprintf(a[7], 80, "-WW@S%i,%i", filedes[0], filedesB[1]);
233 a[8] = NULL;
234
235 p = fork();
236 if (p == -1) {
237 printf("[ start_xterm(): ERROR while trying to "
238 "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 printf("[ start_xterm(): ERROR while trying "
247 "to do a setsid(): %i ]\n", errno);
248
249 res = execvp(a[0], a);
250 printf("[ start_xterm(): ERROR while trying to "
251 "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 if (errno == ENOENT)
260 printf("[ Most probably you don't have xterm"
261 " in your PATH. Try again. ]\n");
262 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 if (!console_handles[handle].in_use_for_input)
327 return 0;
328
329 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 if (!console_handles[handle].in_use_for_input &&
411 !console_handles[handle].outputonly)
412 console_change_inputability(handle, 1);
413
414 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 chp->machine_name = "";
664 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 * 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 * 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 int console_start_slave(struct machine *machine, char *consolename,
701 int use_for_input)
702 {
703 struct console_handle *chp;
704 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 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 }
717 chp->machine_name = strdup(machine->machine_name);
718 chp->name = strdup(consolename);
719
720 if (allow_slaves)
721 chp->using_xterm = USING_XTERM_BUT_NOT_YET_OPEN;
722
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 int console_start_slave_inputonly(struct machine *machine, char *consolename,
740 int use_for_input)
741 {
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 chp->in_use_for_input = use_for_input;
753 chp->machine_name = strdup(machine->name);
754 chp->name = strdup(consolename);
755
756 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 exit(1);
774 }
775
776 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 }
797
798
799 /*
800 * console_init_main():
801 *
802 * Puts the host's console into single-character (non-canonical) mode.
803 */
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 * 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 * 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 * 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 * 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 */
931 int console_warn_if_slaves_are_needed(int init)
932 {
933 int i, n = 0;
934
935 if (allow_slaves)
936 return 0;
937
938 for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
939 if (console_handles[i].in_use &&
940 console_handles[i].in_use_for_input &&
941 !console_handles[i].using_xterm)
942 n ++;
943
944 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 }
961
962 return 0;
963 }
964
965
966 /*
967 * 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 struct settings *console_settings = settings_new();
977
978 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 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
991 chp->in_use_for_input = 1;
992 }
993

  ViewVC Help
Powered by ViewVC 1.1.26