/[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 42 - (hide annotations)
Mon Oct 8 16:22:32 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 23701 byte(s)
++ trunk/HISTORY	(local)
$Id: HISTORY,v 1.1613 2007/06/15 20:11:26 debug Exp $
20070501	Continuing a little on m88k disassembly (control registers,
		more instructions).
		Adding a dummy mvme88k machine mode.
20070502	Re-adding MIPS load/store alignment exceptions.
20070503	Implementing more of the M88K disassembly code.
20070504	Adding disassembly of some more M88K load/store instructions.
		Implementing some relatively simple M88K instructions (br.n,
		xor[.u] imm, and[.u] imm).
20070505	Implementing M88K three-register and, or, xor, and jmp[.n],
		bsr[.n] including function call trace stuff.
		Applying a patch from Bruce M. Simpson which implements the
		SYSCON_BOARD_CPU_CLOCK_FREQ_ID object of the syscon call in
		the yamon PROM emulation.
20070506	Implementing M88K bb0[.n] and bb1[.n], and skeletons for
		ldcr and stcr (although no control regs are implemented yet).
20070509	Found and fixed the bug which caused Linux for QEMU_MIPS to
		stop working in 0.4.5.1: It was a faulty change to the MIPS
		'sc' and 'scd' instructions I made while going through gcc -W
		warnings on 20070428.
20070510	Updating the Linux/QEMU_MIPS section in guestoses.html to
		use mips-test-0.2.tar.gz instead of 0.1.
		A big thank you to Miod Vallat for sending me M88K manuals.
		Implementing more M88K instructions (addu, subu, div[u], mulu,
		ext[u], clr, set, cmp).
20070511	Fixing bugs in the M88K "and" and "and.u" instructions (found
		by comparing against the manual).
		Implementing more M88K instructions (mask[.u], mak, bcnd (auto-
		generated)) and some more control register details.
		Cleanup: Removing the experimental AVR emulation mode and
		corresponding devices; AVR emulation wasn't really meaningful.
		Implementing autogeneration of most M88K loads/stores. The
		rectangle drawing demo (with -O0) for M88K runs :-)
		Beginning on M88K exception handling.
		More M88K instructions: tb0, tb1, rte, sub, jsr[.n].
		Adding some skeleton MVME PROM ("BUG") emulation.
20070512	Fixing a bug in the M88K cmp instruction.
		Adding the M88K lda (scaled register) instruction.
		Fixing bugs in 64-bit (32-bit pairs) M88K loads/stores.
		Removing the unused tick_hz stuff from the machine struct.
		Implementing the M88K xmem instruction. OpenBSD/mvme88k gets
		far enough to display the Copyright banner :-)
		Implementing subu.co (guess), addu.co, addu.ci, ff0, and ff1.
		Adding a dev_mvme187, for MVME187-specific devices/registers.
		OpenBSD/mvme88k prints more boot messages. :)
20070515	Continuing on MVME187 emulation (adding more devices, beginning
		on the CMMUs, etc).
		Adding the M88K and.c, xor.c, and or.c instructions, and making
		sure that mul, div, etc cause exceptions if executed when SFD1
		is disabled.
20070517	Continuing on M88K and MVME187 emulation in general; moving
		the CMMU registers to the CPU struct, separating dev_pcc2 from
		dev_mvme187, and beginning on memory_m88k.c (BATC and PATC).
		Fixing a bug in 64-bit (32-bit pairs) M88K fast stores.
		Implementing the clock part of dev_mk48txx.
		Implementing the M88K fstcr and xcr instructions.
		Implementing m88k_cpu_tlbdump().
		Beginning on the implementation of a separate address space
		for M88K .usr loads/stores.
20070520	Removing the non-working (skeleton) Sandpoint, SonyNEWS, SHARK
		Dnard, and Zaurus machine modes.
		Experimenting with dyntrans to_be_translated read-ahead. It
		seems to give a very small performance increase for MIPS
		emulation, but a large performance degradation for SuperH. Hm.
20070522	Disabling correct SuperH ITLB emulation; it does not seem to be
		necessary in order to let SH4 guest OSes run, and it slows down
		userspace code.
		Implementing "samepage" branches for SuperH emulation, and some
		other minor speed hacks.
20070525	Continuing on M88K memory-related stuff: exceptions, memory
		transaction register contents, etc.
		Implementing the M88K subu.ci instruction.
		Removing the non-working (skeleton) Iyonix machine mode.
		OpenBSD/mvme88k reaches userland :-), starts executing
		/sbin/init's instructions, and issues a few syscalls, before
		crashing.
20070526	Fixing bugs in dev_mk48txx, so that OpenBSD/mvme88k detects
		the correct time-of-day.
		Implementing a generic IRQ controller for the test machines
		(dev_irqc), similar to a proposed patch from Petr Stepan.
		Experimenting some more with translation read-ahead.
		Adding an "expect" script for automated OpenBSD/landisk
		install regression/performance tests.
20070527	Adding a dummy mmEye (SH3) machine mode skeleton.
		FINALLY found the strange M88K bug I have been hunting: I had
		not emulated the SNIP value for exceptions occurring in
		branch delay slots correctly.
		Implementing correct exceptions for 64-bit M88K loads/stores.
		Address to symbol lookups are now disabled when M88K is
		running in usermode (because usermode addresses don't have
		anything to do with supervisor addresses).
20070531	Removing the mmEye machine mode skeleton.
20070604	Some minor code cleanup.
20070605	Moving src/useremul.c into a subdir (src/useremul/), and
		cleaning up some more legacy constructs.
		Adding -Wstrict-aliasing and -fstrict-aliasing detection to
		the configure script.
20070606	Adding a check for broken GCC on Solaris to the configure
		script. (GCC 3.4.3 on Solaris cannot handle static variables
		which are initialized to 0 or NULL. :-/)
		Removing the old (non-working) ARC emulation modes: NEC RD94,
		R94, R96, and R98, and the last traces of Olivetti M700 and
		Deskstation Tyne.
		Removing the non-working skeleton WDSC device (dev_wdsc).
20070607	Thinking about how to use the host's cc + ld at runtime to
		generate native code. (See experiments/native_cc_ld_test.i
		for an example.)
20070608	Adding a program counter sampling timer, which could be useful
		for native code generation experiments.
		The KN02_CSR_NRMMOD bit in the DECstation 5000/200 (KN02) CSR
		should always be set, to allow a 5000/200 PROM to boot.
20070609	Moving out breakpoint details from the machine struct into
		a helper struct, and removing the limit on max nr of
		breakpoints.
20070610	Moving out tick functions into a helper struct as well (which
		also gets rid of the max limit).
20070612	FINALLY figured out why Debian/DECstation stopped working when
		translation read-ahead was enabled: in src/memory_rw.c, the
		call to invalidate_code_translation was made also if the
		memory access was an instruction load (if the page was mapped
		as writable); it shouldn't be called in that case.
20070613	Implementing some more MIPS32/64 revision 2 instructions: di,
		ei, ext, dext, dextm, dextu, and ins.
20070614	Implementing an instruction combination for the NetBSD/arm
		idle loop (making the host not use any cpu if NetBSD/arm
		inside the emulator is not using any cpu).
		Increasing the nr of ARM VPH entries from 128 to 384.
20070615	Removing the ENABLE_arch stuff from the configure script, so
		that all included architectures are included in both release
		and development builds.
		Moving memory related helper functions from misc.c to memory.c.
		Adding preliminary instructions for netbooting NetBSD/pmppc to
		guestoses.html; it doesn't work yet, there are weird timeouts.
		Beginning a total rewrite of the userland emulation modes
		(removing all emulation modes, beginning from scratch with
		NetBSD/MIPS and FreeBSD/Alpha only).
20070616	After fixing a bug in the DEC21143 NIC (the TDSTAT_OWN bit was
		only cleared for the last segment when transmitting, not all
		segments), NetBSD/pmppc boots with root-on-nfs without the
		timeouts. Updating guestoses.html.
		Removing the skeleton PSP (Playstation Portable) mode.
		Moving X11-related stuff in the machine struct into a helper
		struct.
		Cleanup of out-of-memory checks, to use a new CHECK_ALLOCATION
		macro (which prints a meaningful error message).
		Adding a COMMENT to each machine and device (for automagic
		.index comment generation).
		Doing regression testing for the next release.

==============  RELEASE 0.4.6  ==============


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

  ViewVC Help
Powered by ViewVC 1.1.26