/[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 42 - (show 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 /*
2 * Copyright (C) 2003-2007 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.26 2007/06/15 18:07:33 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 #include <time.h>
74
75 #include "console.h"
76 #include "emul.h"
77 #include "machine.h"
78 #include "settings.h"
79
80
81 extern char *progname;
82 extern int verbose;
83 extern struct settings *global_settings;
84
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 static struct settings *console_settings = NULL;
95 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 int in_use_for_input;
110 int using_xterm;
111 int inputonly;
112 int outputonly;
113 int warning_printed;
114
115 char *machine_name;
116 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 * console_deinit_main():
137 *
138 * Restore host's console settings.
139 */
140 void console_deinit_main(void)
141 {
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 * 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 */
160 void console_sigcont(int x)
161 {
162 if (!console_initialized)
163 return;
164
165 /* Make sure that the correct (current) termios setting is active: */
166 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 * 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 */
182 static void start_xterm(int handle)
183 {
184 int filedes[2];
185 int filedesB[2];
186 int res;
187 size_t mlen;
188 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 CHECK_ALLOCATION(a = malloc(sizeof(char *) * 20));
208
209 a[0] = getenv("XTERM");
210 if (a[0] == NULL)
211 a[0] = "xterm";
212 a[1] = "-geometry";
213 a[2] = "80x25";
214 a[3] = "-title";
215 mlen = strlen(console_handles[handle].name) +
216 strlen(console_handles[handle].machine_name) + 30;
217 CHECK_ALLOCATION(a[4] = malloc(mlen));
218 snprintf(a[4], mlen, "GXemul: %s %s",
219 console_handles[handle].machine_name,
220 console_handles[handle].name);
221 a[5] = "-e";
222 a[6] = progname;
223 CHECK_ALLOCATION(a[7] = malloc(80));
224 snprintf(a[7], 80, "-WW@S%i,%i", filedes[0], filedesB[1]);
225 a[8] = NULL;
226
227 p = fork();
228 if (p == -1) {
229 printf("[ start_xterm(): ERROR while trying to "
230 "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 printf("[ start_xterm(): ERROR while trying "
239 "to do a setsid(): %i ]\n", errno);
240
241 res = execvp(a[0], a);
242 printf("[ start_xterm(): ERROR while trying to "
243 "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 if (errno == ENOENT)
252 printf("[ Most probably you don't have xterm"
253 " in your PATH. Try again. ]\n");
254 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 if (!console_handles[handle].in_use_for_input)
319 return 0;
320
321 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 if (!console_handles[handle].in_use_for_input &&
403 !console_handles[handle].outputonly)
404 console_change_inputability(handle, 1);
405
406 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 char buf[16384];
541
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 usleep(10000);
587 }
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 CHECK_ALLOCATION(console_handles =
615 realloc(console_handles, sizeof(
616 struct console_handle) * (n_console_handles + 1)));
617 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 chp->machine_name = "";
626 CHECK_ALLOCATION(chp->name = strdup(name));
627
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 * 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 * 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 int console_start_slave(struct machine *machine, char *consolename,
659 int use_for_input)
660 {
661 struct console_handle *chp;
662 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 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 }
675
676 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
683 CHECK_ALLOCATION(chp->name = strdup(consolename));
684
685 if (allow_slaves)
686 chp->using_xterm = USING_XTERM_BUT_NOT_YET_OPEN;
687
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 int console_start_slave_inputonly(struct machine *machine, char *consolename,
705 int use_for_input)
706 {
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 chp->in_use_for_input = use_for_input;
718 CHECK_ALLOCATION(chp->machine_name = strdup(machine->name));
719 CHECK_ALLOCATION(chp->name = strdup(consolename));
720
721 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 exit(1);
739 }
740
741 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 }
762
763
764 /*
765 * console_init_main():
766 *
767 * Puts the host's console into single-character (non-canonical) mode.
768 */
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 * 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 * 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 * 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 * 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 */
896 int console_warn_if_slaves_are_needed(int init)
897 {
898 int i, n = 0;
899
900 if (allow_slaves)
901 return 0;
902
903 for (i=MAIN_CONSOLE+1; i<n_console_handles; i++)
904 if (console_handles[i].in_use &&
905 console_handles[i].in_use_for_input &&
906 !console_handles[i].using_xterm)
907 n ++;
908
909 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 }
926
927 return 0;
928 }
929
930
931 /*
932 * 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 console_settings = settings_new();
943
944 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 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
957 chp->in_use_for_input = 1;
958 }
959
960
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