/[dynamips]/upstream/dynamips-0.2.6-RC3/dev_vtty.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 /upstream/dynamips-0.2.6-RC3/dev_vtty.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 4 - (show annotations)
Sat Oct 6 16:06:49 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 27096 byte(s)
dynamips-0.2.6-RC3

1 /*
2 * Cisco 7200 (Predator) simulation platform.
3 * Copyright (c) 2005,2006 Christophe Fillot (cf@utc.fr)
4 *
5 * Virtual console TTY.
6 *
7 * "Interactive" part idea by Mtve.
8 * TCP console added by Mtve.
9 * Serial console by Peter Ross (suxen_drol@hotmail.com)
10 */
11
12 /* By default, Cygwin supports only 64 FDs with select()! */
13 #ifdef __CYGWIN__
14 #define FD_SETSIZE 1024
15 #endif
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <termios.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 #include <assert.h>
27
28 #include <arpa/telnet.h>
29
30 #include "mips64.h"
31 #include "cp0.h"
32 #include "cpu.h"
33 #include "dynamips.h"
34 #include "mips64_exec.h"
35 #include "device.h"
36 #include "memory.h"
37 #include "dev_c7200.h"
38 #include "dev_c3600.h"
39 #include "dev_vtty.h"
40 #include "vm.h"
41 #include "utils.h"
42
43 /* VTTY list */
44 static pthread_mutex_t vtty_list_mutex = PTHREAD_MUTEX_INITIALIZER;
45 static vtty_t *vtty_list = NULL;
46 static pthread_t vtty_thread;
47
48 #define VTTY_LIST_LOCK() pthread_mutex_lock(&vtty_list_mutex);
49 #define VTTY_LIST_UNLOCK() pthread_mutex_unlock(&vtty_list_mutex);
50
51 static struct termios tios,tios_orig;
52
53 /* Send Telnet command: WILL TELOPT_ECHO */
54 static void vtty_telnet_will_echo(vtty_t *vtty)
55 {
56 u_char cmd[] = { IAC, WILL, TELOPT_ECHO };
57 write(vtty->fd,cmd,sizeof(cmd));
58 }
59
60 /* Send Telnet command: Suppress Go-Ahead */
61 static void vtty_telnet_will_suppress_go_ahead(vtty_t *vtty)
62 {
63 u_char cmd[] = { IAC, WILL, TELOPT_SGA };
64 write(vtty->fd,cmd,sizeof(cmd));
65 }
66
67 /* Send Telnet command: Don't use linemode */
68 static void vtty_telnet_dont_linemode(vtty_t *vtty)
69 {
70 u_char cmd[] = { IAC, DONT, TELOPT_LINEMODE };
71 write(vtty->fd,cmd,sizeof(cmd));
72 }
73
74 /* Send Telnet command: does the client support terminal type message? */
75 static void vtty_telnet_do_ttype(vtty_t *vtty)
76 {
77 u_char cmd[] = { IAC, DO, TELOPT_TTYPE };
78 write(vtty->fd,cmd,sizeof(cmd));
79 }
80
81 /* Restore TTY original settings */
82 static void vtty_term_reset(void)
83 {
84 tcsetattr(STDIN_FILENO,TCSANOW,&tios_orig);
85 }
86
87 /* Initialize real TTY */
88 static void vtty_term_init(void)
89 {
90 tcgetattr(STDIN_FILENO,&tios);
91
92 memcpy(&tios_orig,&tios,sizeof(struct termios));
93 atexit(vtty_term_reset);
94
95 tios.c_cc[VTIME] = 0;
96 tios.c_cc[VMIN] = 1;
97
98 /* Disable Ctrl-C, Ctrl-S, Ctrl-Q and Ctrl-Z */
99 tios.c_cc[VINTR] = 0;
100 tios.c_cc[VSTART] = 0;
101 tios.c_cc[VSTOP] = 0;
102 tios.c_cc[VSUSP] = 0;
103
104 tios.c_lflag &= ~(ICANON|ECHO);
105 tios.c_iflag &= ~ICRNL;
106 tcsetattr(STDIN_FILENO, TCSANOW, &tios);
107 tcflush(STDIN_FILENO,TCIFLUSH);
108 }
109
110 /* Wait for a TCP connection */
111 static int vtty_tcp_conn_wait(vtty_t *vtty)
112 {
113 struct sockaddr_in serv;
114 int one = 1;
115
116 vtty->state = VTTY_STATE_TCP_INVALID;
117
118 if ((vtty->accept_fd = socket(PF_INET,SOCK_STREAM,0)) < 0) {
119 perror("vtty_tcp_waitcon: socket");
120 return(-1);
121 }
122
123 if (setsockopt(vtty->accept_fd,SOL_SOCKET,SO_REUSEADDR,
124 &one,sizeof(one)) < 0)
125 {
126 perror("vtty_tcp_waitcon: setsockopt(SO_REUSEADDR)");
127 goto error;
128 }
129
130 memset(&serv,0,sizeof(serv));
131 serv.sin_family = AF_INET;
132 serv.sin_addr.s_addr = htonl(INADDR_ANY);
133 serv.sin_port = htons(vtty->tcp_port);
134
135 if (bind(vtty->accept_fd,(struct sockaddr *)&serv,sizeof(serv)) < 0) {
136 perror("vtty_tcp_waitcon: bind");
137 goto error;
138 }
139
140 if (listen(vtty->accept_fd,1) < 0) {
141 perror("vtty_tcp_waitcon: listen");
142 goto error;
143 }
144
145 vm_log(vtty->vm,"VTTY","%s: waiting connection on tcp port %d (FD %d)\n",
146 vtty->name,vtty->tcp_port,vtty->accept_fd);
147
148 vtty->select_fd = &vtty->accept_fd;
149 vtty->state = VTTY_STATE_TCP_WAITING;
150 return(0);
151
152 error:
153 close(vtty->accept_fd);
154 vtty->accept_fd = -1;
155 vtty->select_fd = NULL;
156 return(-1);
157 }
158
159 /* Accept a TCP connection */
160 static int vtty_tcp_conn_accept(vtty_t *vtty)
161 {
162 if ((vtty->fd = accept(vtty->accept_fd,NULL,NULL)) < 0) {
163 fprintf(stderr,"vtty_tcp_conn_accept: accept on port %d failed %s\n",
164 vtty->tcp_port,strerror(errno));
165 return(-1);
166 }
167
168 vm_log(vtty->vm,"VTTY","%s is now connected (accept_fd=%d,conn_fd=%d)\n",
169 vtty->name,vtty->accept_fd,vtty->fd);
170
171 /* Adapt Telnet settings */
172 if (vtty->terminal_support) {
173 vtty_telnet_do_ttype(vtty);
174 vtty_telnet_will_echo(vtty);
175 vtty_telnet_will_suppress_go_ahead(vtty);
176 vtty_telnet_dont_linemode(vtty);
177 vtty->input_state = VTTY_INPUT_TELNET;
178 }
179
180 if (!(vtty->fstream = fdopen(vtty->fd, "wb"))) {
181 close(vtty->fd);
182 vtty->fd = -1;
183 return(-1);
184 }
185
186 fprintf(vtty->fstream,
187 "Connected to Dynamips VM \"%s\" (ID %u, type %s) - %s\r\n\r\n",
188 vtty->vm->name, vtty->vm->instance_id, vm_get_type(vtty->vm),
189 vtty->name);
190
191 vtty->select_fd = &vtty->fd;
192 vtty->state = VTTY_STATE_TCP_RUNNING;
193 return(0);
194 }
195
196 /*
197 * Parse serial interface descriptor string, return 0 if success
198 * string takes the form "device:baudrate:databits:parity:stopbits:hwflow"
199 * device is mandatory, other options are optional (default=9600,8,N,1,0).
200 */
201 int vtty_parse_serial_option(vtty_serial_option_t *option, char *optarg)
202 {
203 char *array[6];
204 int count;
205
206 if ((count = m_strtok(optarg, ':', array, 6)) < 1) {
207 fprintf(stderr,"vtty_parse_serial_option: invalid string\n");
208 return(-1);
209 }
210
211 if (!(option->device = strdup(array[0]))) {
212 fprintf(stderr,"vtty_parse_serial_option: unable to copy string\n");
213 return(-1);
214 }
215
216 option->baudrate = (count>1) ? atoi(array[1]) : 9600;
217 option->databits = (count>2) ? atoi(array[2]) : 8;
218
219 if (count > 3) {
220 switch(*array[3]) {
221 case 'o':
222 case 'O':
223 option->parity = 1; /* odd */
224 case 'e':
225 case 'E':
226 option->parity = 2; /* even */
227 default:
228 option->parity = 0; /* none */
229 }
230 } else {
231 option->parity = 0;
232 }
233
234 option->stopbits = (count>4) ? atoi(array[4]) : 1;
235 option->hwflow = (count>5) ? atoi(array[5]) : 0;
236 return(0);
237 }
238
239 #if defined(__CYGWIN__) || defined(SUNOS)
240 void cfmakeraw(struct termios *termios_p) {
241 termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|
242 INLCR|IGNCR|ICRNL|IXON);
243 termios_p->c_oflag &= ~OPOST;
244 termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
245 termios_p->c_cflag &= ~(CSIZE|PARENB);
246 termios_p->c_cflag |= CS8;
247 }
248 #endif
249
250 /*
251 * Setup serial port, return 0 if success.
252 */
253 static int vtty_serial_setup(vtty_t *vtty, const vtty_serial_option_t *option)
254 {
255 struct termios tio;
256 int tio_baudrate;
257
258 if (tcgetattr(vtty->fd, &tio) != 0) {
259 fprintf(stderr, "error: tcgetattr failed\n");
260 return(-1);
261 }
262
263 cfmakeraw(&tio);
264
265 tio.c_cflag = 0
266 |CLOCAL // ignore modem control lines
267 ;
268
269 tio.c_cflag &= ~CREAD;
270 tio.c_cflag |= CREAD;
271
272 switch(option->baudrate) {
273 case 50 : tio_baudrate = B50; break;
274 case 75 : tio_baudrate = B75; break;
275 case 110 : tio_baudrate = B110; break;
276 case 134 : tio_baudrate = B134; break;
277 case 150 : tio_baudrate = B150; break;
278 case 200 : tio_baudrate = B200; break;
279 case 300 : tio_baudrate = B300; break;
280 case 600 : tio_baudrate = B600; break;
281 case 1200 : tio_baudrate = B1200; break;
282 case 1800 : tio_baudrate = B1800; break;
283 case 2400 : tio_baudrate = B2400; break;
284 case 4800 : tio_baudrate = B4800; break;
285 case 9600 : tio_baudrate = B9600; break;
286 case 19200 : tio_baudrate = B19200; break;
287 case 38400 : tio_baudrate = B38400; break;
288 case 57600 : tio_baudrate = B57600; break;
289 #if defined(B76800)
290 case 76800 : tio_baudrate = B76800; break;
291 #endif
292 case 115200 : tio_baudrate = B115200; break;
293 #if defined(B230400)
294 case 230400 : tio_baudrate = B230400; break;
295 #endif
296 default:
297 fprintf(stderr, "error: unsupported baudrate\n");
298 return(-1);
299 }
300
301 cfsetospeed(&tio, tio_baudrate);
302 cfsetispeed(&tio, tio_baudrate);
303
304 tio.c_cflag &= ~CSIZE; /* clear size flag */
305 switch(option->databits) {
306 case 5 : tio.c_cflag |= CS5; break;
307 case 6 : tio.c_cflag |= CS6; break;
308 case 7 : tio.c_cflag |= CS7; break;
309 case 8 : tio.c_cflag |= CS8; break;
310 default :
311 fprintf(stderr, "error: unsupported databits\n");
312 return(-1);
313 }
314
315 tio.c_iflag &= ~INPCK; /* clear parity flag */
316 tio.c_cflag &= ~(PARENB|PARODD);
317 switch(option->parity) {
318 case 0 : break;
319 case 2 : tio.c_iflag|=INPCK; tio.c_cflag|=PARENB; break; /* even */
320 case 1 : tio.c_iflag|=INPCK; tio.c_cflag|=PARENB|PARODD; break; /* odd */
321 default:
322 fprintf(stderr, "error: unsupported parity\n");
323 return(-1);
324 }
325
326 tio.c_cflag &= ~CSTOPB; /* clear stop flag */
327 switch(option->stopbits) {
328 case 1 : break;
329 case 2 : tio.c_cflag |= CSTOPB; break;
330 default :
331 fprintf(stderr, "error: unsupported stopbits\n");
332 return(-1);
333 }
334
335 #if defined(CRTSCTS)
336 tio.c_cflag &= ~CRTSCTS;
337 #endif
338 #if defined(CNEW_RTSCTS)
339 tio.c_cflag &= ~CNEW_RTSCTS;
340 #endif
341 if (option->hwflow) {
342 #if defined(CRTSCTS)
343 tio.c_cflag |= CRTSCTS;
344 #else
345 tio.c_cflag |= CNEW_RTSCTS;
346 #endif
347 }
348
349 tio.c_cc[VTIME] = 0;
350 tio.c_cc[VMIN] = 1; /* block read() until one character is available */
351
352 #if 0
353 /* not neccessary unless O_NONBLOCK used */
354 if (fcntl(vtty->fd, F_SETFL, 0) != 0) { /* enable blocking mode */
355 fprintf(stderr, "error: fnctl F_SETFL failed\n");
356 return(-1);
357 }
358 #endif
359
360 if (tcflush(vtty->fd, TCIOFLUSH) != 0) {
361 fprintf(stderr, "error: tcflush failed\n");
362 return(-1);
363 }
364
365 if (tcsetattr(vtty->fd, TCSANOW, &tio) != 0 ) {
366 fprintf(stderr, "error: tcsetattr failed\n");
367 return(-1);
368 }
369
370 return(0);
371 }
372
373 /* Create a virtual tty */
374 vtty_t *vtty_create(vm_instance_t *vm,char *name,int type,int tcp_port,
375 const vtty_serial_option_t *option)
376 {
377 vtty_t *vtty;
378
379 if (!(vtty = malloc(sizeof(*vtty)))) {
380 fprintf(stderr,"VTTY: unable to create new virtual tty.\n");
381 return NULL;
382 }
383
384 memset(vtty,0,sizeof(*vtty));
385 vtty->name = name;
386 vtty->type = type;
387 vtty->vm = vm;
388 vtty->fd = -1;
389 vtty->fstream = NULL;
390 vtty->accept_fd = -1;
391 pthread_mutex_init(&vtty->lock,NULL);
392 vtty->terminal_support = 1;
393 vtty->input_state = VTTY_INPUT_TEXT;
394
395 switch (vtty->type) {
396 case VTTY_TYPE_NONE:
397 vtty->select_fd = NULL;
398 break;
399
400 case VTTY_TYPE_TERM:
401 vtty_term_init();
402 vtty->fd = STDIN_FILENO;
403 vtty->select_fd = &vtty->fd;
404 vtty->fstream = stdout;
405 break;
406
407 case VTTY_TYPE_TCP:
408 vtty->tcp_port = tcp_port;
409 vtty_tcp_conn_wait(vtty);
410 break;
411
412 case VTTY_TYPE_SERIAL:
413 vtty->fd = open(option->device, O_RDWR);
414 if (vtty->fd < 0) {
415 fprintf(stderr,"VTTY: open failed\n");
416 free(vtty);
417 return NULL;
418 }
419 if (vtty_serial_setup(vtty,option)) {
420 fprintf(stderr,"VTTY: setup failed\n");
421 close(vtty->fd);
422 free(vtty);
423 return NULL;
424 }
425 vtty->select_fd = &vtty->fd;
426 vtty->terminal_support = 0;
427 break;
428
429 default:
430 fprintf(stderr,"tty_create: bad vtty type %d\n",vtty->type);
431 return NULL;
432 }
433
434 /* Add this new VTTY to the list */
435 VTTY_LIST_LOCK();
436 vtty->next = vtty_list;
437 vtty->pprev = &vtty_list;
438
439 if (vtty_list != NULL)
440 vtty_list->pprev = &vtty->next;
441
442 vtty_list = vtty;
443 VTTY_LIST_UNLOCK();
444 return vtty;
445 }
446
447 /* Delete a virtual tty */
448 void vtty_delete(vtty_t *vtty)
449 {
450 if (vtty != NULL) {
451 if (vtty->pprev != NULL) {
452 VTTY_LIST_LOCK();
453 if (vtty->next)
454 vtty->next->pprev = vtty->pprev;
455 *(vtty->pprev) = vtty->next;
456 VTTY_LIST_UNLOCK();
457 }
458
459 if ((vtty->fstream) && (vtty->fstream != stdout))
460 fclose(vtty->fstream);
461
462 /* We don't close FD 0 since it is stdin */
463 if (vtty->fd > 0) {
464 vm_log(vtty->vm,"VTTY","%s: closing FD %d\n",vtty->name,vtty->fd);
465 close(vtty->fd);
466 }
467
468 if (vtty->accept_fd != -1) {
469 vm_log(vtty->vm,"VTTY","%s: closing accept FD %d\n",
470 vtty->name,vtty->accept_fd);
471 close(vtty->accept_fd);
472 }
473
474 free(vtty);
475 }
476 }
477
478 /* Store a character in the FIFO buffer */
479 static int vtty_store(vtty_t *vtty,u_char c)
480 {
481 u_int nwptr;
482
483 VTTY_LOCK(vtty);
484 nwptr = vtty->write_ptr + 1;
485 if (nwptr == VTTY_BUFFER_SIZE)
486 nwptr = 0;
487
488 if (nwptr == vtty->read_ptr) {
489 VTTY_UNLOCK(vtty);
490 return(-1);
491 }
492
493 vtty->buffer[vtty->write_ptr] = c;
494 vtty->write_ptr = nwptr;
495 VTTY_UNLOCK(vtty);
496 return(0);
497 }
498
499 /* Store a string in the FIFO buffer */
500 int vtty_store_str(vtty_t *vtty,char *str)
501 {
502 if (!vtty)
503 return(0);
504
505 while(*str != 0) {
506 if (vtty_store(vtty,*str) == -1)
507 return(-1);
508
509 str++;
510 }
511
512 vtty->input_pending = TRUE;
513 return(0);
514 }
515
516 /* Store CTRL+C in buffer */
517 int vtty_store_ctrlc(vtty_t *vtty)
518 {
519 if (vtty)
520 vtty_store(vtty,0x03);
521 return(0);
522 }
523
524 /*
525 * Read a character from the terminal.
526 */
527 static int vtty_term_read(vtty_t *vtty)
528 {
529 u_char c;
530
531 if (read(vtty->fd,&c,1) == 1)
532 return(c);
533
534 perror("read from vtty failed");
535 return(-1);
536 }
537
538 /*
539 * Read a character from the TCP connection.
540 */
541 static int vtty_tcp_read(vtty_t *vtty)
542 {
543 u_char c;
544
545 switch(vtty->state) {
546 case VTTY_STATE_TCP_RUNNING:
547 if (read(vtty->fd,&c,1) == 1)
548 return(c);
549
550 /* Problem with the connection: Re-enter wait mode */
551 shutdown(vtty->fd,2);
552 fclose(vtty->fstream);
553 close(vtty->fd);
554 vtty->fstream = NULL;
555 vtty->fd = -1;
556 vtty->select_fd = &vtty->accept_fd;
557 vtty->state = VTTY_STATE_TCP_WAITING;
558 return(-1);
559
560 case VTTY_STATE_TCP_WAITING:
561 /* A new connection has arrived */
562 vtty_tcp_conn_accept(vtty);
563 return(-1);
564 }
565
566 /* Shouldn't happen... */
567 return(-1);
568 }
569
570 /*
571 * Read a character from the virtual TTY.
572 *
573 * If the VTTY is a TCP connection, restart it in case of error.
574 */
575 static int vtty_read(vtty_t *vtty)
576 {
577 switch(vtty->type) {
578 case VTTY_TYPE_TERM:
579 case VTTY_TYPE_SERIAL:
580 return(vtty_term_read(vtty));
581 case VTTY_TYPE_TCP:
582 return(vtty_tcp_read(vtty));
583 default:
584 fprintf(stderr,"vtty_read: bad vtty type %d\n",vtty->type);
585 return(-1);
586 }
587
588 /* NOTREACHED */
589 return(-1);
590 }
591
592 /* Process remote control char */
593 static void remote_control(vtty_t *vtty,u_char c)
594 {
595 vm_instance_t *vm = vtty->vm;
596 cpu_mips_t *cpu0 = cpu_group_find_id(vm->cpu_group,0);
597
598 switch(c) {
599 /* Show the object list */
600 case 'o':
601 vm_object_dump(vm);
602 break;
603
604 /* Stop the MIPS VM */
605 case 'q':
606 vm->status = VM_STATUS_SHUTDOWN;
607 break;
608
609 /* Reboot the C7200 */
610 case 'k':
611 if (vm->type == VM_TYPE_C7200)
612 c7200_boot_ios(VM_C7200(vm));
613 break;
614
615 /* Show the device list */
616 case 'd':
617 dev_show_list(vm);
618 pci_dev_show_list(vm->pci_bus[0]);
619 pci_dev_show_list(vm->pci_bus[1]);
620 break;
621
622 /* Show info about Port Adapters or Network Modules */
623 case 'p':
624 switch(vm->type) {
625 case VM_TYPE_C3600:
626 c3600_nm_show_all_info(VM_C3600(vm));
627 break;
628 case VM_TYPE_C7200:
629 c7200_pa_show_all_info(VM_C7200(vm));
630 break;
631 }
632 break;
633
634 /* Dump the MIPS registers */
635 case 'r':
636 if (cpu0) mips64_dump_regs(cpu0);
637 break;
638
639 /* Dump the latest memory accesses */
640 case 'm':
641 if (cpu0) memlog_dump(cpu0);
642 break;
643
644 /* Suspend CPU emulation */
645 case 's':
646 vm_suspend(vm);
647 break;
648
649 /* Resume CPU emulation */
650 case 'u':
651 vm_resume(vm);
652 break;
653
654 /* Dump the MIPS TLB */
655 case 't':
656 if (cpu0) tlb_dump(cpu0);
657 break;
658
659 /* Dump the MIPS TLB (raw mode) */
660 case 'z':
661 if (cpu0) tlb_raw_dump(cpu0);
662 break;
663
664 /* Show information about JIT compiled pages */
665 case 'b':
666 if (cpu0) {
667 printf("\nCPU0: %u JIT compiled pages "
668 "[Exec Area Pages: %lu/%lu]\n",
669 cpu0->compiled_pages,
670 (u_long)cpu0->exec_page_alloc,
671 (u_long)cpu0->exec_page_count);
672 }
673 break;
674
675 /* MTS64 cache statistics */
676 case 'l':
677 if (cpu0) {
678 cpu0->mts_show_stats(cpu0);
679 }
680 break;
681
682 /* Extract the configuration from the NVRAM */
683 case 'c':
684 vm_ios_save_config(vm);
685 break;
686
687 /* Non-JIT mode statistics */
688 case 'j':
689 if (cpu0) mips64_dump_stats(cpu0);
690 break;
691
692 /* Determine an idle pointer counter */
693 case 'i':
694 if (cpu0) {
695 mips64_get_idling_pc(cpu0);
696 }
697 break;
698
699 /* Experimentations / Tests */
700 case 'x':
701 if (cpu0) {
702 /* IRQ triggering */
703 mips64_set_irq(cpu0,2/*C7200_PA_MGMT_IRQ*/);
704 //mips64_set_irq(cpu0,3/*C7200_PA_MGMT_IRQ*/);
705 //mips64_set_irq(cpu0,C7200_PA_MGMT_IRQ);
706 }
707 break;
708
709 /* Twice Ctrl + ']' (0x1d, 29), or Alt-Gr + '*' (0xb3, 179) */
710 case 0x1d:
711 case 0xb3:
712 vtty_store(vtty,c);
713 break;
714
715 default:
716 printf("\n\nInstance %s (ID %d)\n\n",vm->name,vm->instance_id);
717
718 printf("o - Show the VM object list\n"
719 "d - Show the device list\n"
720 "r - Dump MIPS CPU registers\n"
721 "t - Dump MIPS TLB entries\n"
722 "z - Dump MIPS TLB entries (raw mode)\n"
723 "m - Dump the latest memory accesses\n"
724 "s - Suspend CPU emulation\n"
725 "u - Resume CPU emulation\n"
726 "q - Quit the emulator\n"
727 "k - Reboot the virtual machine\n"
728 "b - Show info about JIT compiled pages\n"
729 "l - MTS64 cache statistics\n"
730 "c - Write IOS configuration to disk\n"
731 "j - Non-JIT mode statistics\n"
732 "i - Determine an idling pointer counter\n"
733 "x - Experimentations (can crash the box!)\n"
734 "^] - Send ^]\n"
735 "Other - This help\n");
736 }
737 }
738
739
740 /* Read a character (until one is available) and store it in buffer */
741 static void vtty_read_and_store(vtty_t *vtty)
742 {
743 int c;
744
745 /* wait until we get a character input */
746 c = vtty_read(vtty);
747
748 /* if read error, do nothing */
749 if (c < 0) return;
750
751 if (!vtty->terminal_support) {
752 vtty_store(vtty,c);
753 return;
754 }
755
756 switch(vtty->input_state) {
757 case VTTY_INPUT_TEXT :
758 switch(c) {
759 case 0x1b:
760 vtty->input_state = VTTY_INPUT_VT1;
761 return;
762
763 /* Ctrl + ']' (0x1d, 29), or Alt-Gr + '*' (0xb3, 179) */
764 case 0x1d:
765 case 0xb3:
766 vtty->input_state = VTTY_INPUT_REMOTE;
767 return;
768 case IAC :
769 vtty->input_state = VTTY_INPUT_TELNET;
770 return;
771 case 0: /* NULL - Must be ignored - generated by Linux telnet */
772 case 10: /* LF (Line Feed) - Must be ignored on Windows platform */
773 return;
774 default:
775 /* Store a standard character */
776 vtty_store(vtty,c);
777 return;
778 }
779
780 case VTTY_INPUT_VT1 :
781 switch(c) {
782 case 0x5b:
783 vtty->input_state = VTTY_INPUT_VT2;
784 return;
785 default:
786 vtty_store(vtty,0x1b);
787 vtty_store(vtty,c);
788 }
789 vtty->input_state = VTTY_INPUT_TEXT;
790 return;
791
792 case VTTY_INPUT_VT2 :
793 switch(c) {
794 case 0x41: /* Up Arrow */
795 vtty_store(vtty,16);
796 break;
797 case 0x42: /* Down Arrow */
798 vtty_store(vtty,14);
799 break;
800 case 0x43: /* Right Arrow */
801 vtty_store(vtty,6);
802 break;
803 case 0x44: /* Left Arrow */
804 vtty_store(vtty,2);
805 break;
806 default:
807 vtty_store(vtty,0x5b);
808 vtty_store(vtty,0x1b);
809 vtty_store(vtty,c);
810 break;
811 }
812 vtty->input_state = VTTY_INPUT_TEXT;
813 return;
814
815 case VTTY_INPUT_REMOTE :
816 remote_control(vtty, c);
817 vtty->input_state = VTTY_INPUT_TEXT;
818 return;
819
820 case VTTY_INPUT_TELNET :
821 vtty->telnet_cmd = c;
822 switch(c) {
823 case WILL:
824 case WONT:
825 case DO:
826 case DONT:
827 vtty->input_state = VTTY_INPUT_TELNET_IYOU;
828 return;
829 case SB :
830 vtty->telnet_cmd = c;
831 vtty->input_state = VTTY_INPUT_TELNET_SB1;
832 return;
833 case SE:
834 break;
835 case IAC :
836 vtty_store(vtty, IAC);
837 break;
838 }
839 vtty->input_state = VTTY_INPUT_TEXT;
840 return;
841
842 case VTTY_INPUT_TELNET_IYOU :
843 vtty->telnet_opt = c;
844 /* if telnet client can support ttype, ask it to send ttype string */
845 if ((vtty->telnet_cmd == WILL) &&
846 (vtty->telnet_opt == TELOPT_TTYPE))
847 {
848 vtty_put_char(vtty, IAC);
849 vtty_put_char(vtty, SB);
850 vtty_put_char(vtty, TELOPT_TTYPE);
851 vtty_put_char(vtty, TELQUAL_SEND);
852 vtty_put_char(vtty, IAC);
853 vtty_put_char(vtty, SE);
854 }
855 vtty->input_state = VTTY_INPUT_TEXT;
856 return;
857
858 case VTTY_INPUT_TELNET_SB1 :
859 vtty->telnet_opt = c;
860 vtty->input_state = VTTY_INPUT_TELNET_SB2;
861 return;
862
863 case VTTY_INPUT_TELNET_SB2 :
864 vtty->telnet_qual = c;
865 if ((vtty->telnet_opt == TELOPT_TTYPE) &&
866 (vtty->telnet_qual == TELQUAL_IS))
867 vtty->input_state = VTTY_INPUT_TELNET_SB_TTYPE;
868 else
869 vtty->input_state = VTTY_INPUT_TELNET_NEXT;
870 return;
871
872 case VTTY_INPUT_TELNET_SB_TTYPE :
873 /* parse ttype string: first char is sufficient */
874 /* if client is xterm or vt, set the title bar */
875 if ((c == 'x') || (c == 'X') || (c == 'v') || (c == 'V')) {
876 fprintf(vtty->fstream, "\033]0;Dynamips(%i): %s, %s\07",
877 vtty->vm->instance_id, vtty->vm->name, vtty->name);
878 }
879 vtty->input_state = VTTY_INPUT_TELNET_NEXT;
880 return;
881
882 case VTTY_INPUT_TELNET_NEXT :
883 /* ignore all chars until next IAC */
884 if (c == IAC)
885 vtty->input_state = VTTY_INPUT_TELNET;
886 return;
887 }
888 }
889
890 /* Read a character from the buffer (-1 if the buffer is empty) */
891 int vtty_get_char(vtty_t *vtty)
892 {
893 u_char c;
894
895 VTTY_LOCK(vtty);
896
897 if (vtty->read_ptr == vtty->write_ptr) {
898 VTTY_UNLOCK(vtty);
899 return(-1);
900 }
901
902 c = vtty->buffer[vtty->read_ptr++];
903
904 if (vtty->read_ptr == VTTY_BUFFER_SIZE)
905 vtty->read_ptr = 0;
906
907 VTTY_UNLOCK(vtty);
908 return(c);
909 }
910
911 /* Returns TRUE if a character is available in buffer */
912 int vtty_is_char_avail(vtty_t *vtty)
913 {
914 int res;
915
916 VTTY_LOCK(vtty);
917 res = (vtty->read_ptr != vtty->write_ptr);
918 VTTY_UNLOCK(vtty);
919 return(res);
920 }
921
922 /* put char to vtty */
923 void vtty_put_char(vtty_t *vtty, char ch)
924 {
925 switch(vtty->type) {
926 case VTTY_TYPE_NONE:
927 break;
928
929 case VTTY_TYPE_TERM:
930 fwrite(&ch, 1, 1, vtty->fstream);
931 break;
932
933 case VTTY_TYPE_TCP:
934 if ((vtty->state == VTTY_STATE_TCP_RUNNING) &&
935 (fwrite(&ch, 1, 1, vtty->fstream) != 1))
936 {
937 vm_log(vtty->vm,"VTTY","%s: put char %d failed (%s)\n",
938 vtty->name,(int)ch,strerror(errno));
939 }
940 break;
941
942 case VTTY_TYPE_SERIAL:
943 if (write(vtty->fd,&ch,1) != 1) {
944 vm_log(vtty->vm,"VTTY","%s: put char 0x%x failed (%s)\n",
945 vtty->name,(int)ch,strerror(errno));
946 }
947 break;
948
949 default:
950 fprintf(stderr,"vtty_put_char: bad vtty type %d\n",vtty->type);
951 exit(1);
952 }
953 }
954
955 /* Flush VTTY output */
956 void vtty_flush(vtty_t *vtty)
957 {
958 switch(vtty->type) {
959 case VTTY_TYPE_TERM:
960 case VTTY_TYPE_TCP:
961 if (vtty->fstream)
962 fflush(vtty->fstream);
963 break;
964
965 case VTTY_TYPE_SERIAL:
966 fsync(vtty->fd);
967 break;
968 }
969 }
970
971 /* VTTY thread */
972 static void *vtty_thread_main(void *arg)
973 {
974 vtty_t *vtty;
975 struct timeval tv;
976 int fd,fd_max,res;
977 fd_set rfds;
978
979 for(;;) {
980 VTTY_LIST_LOCK();
981
982 /* Build the FD set */
983 FD_ZERO(&rfds);
984 fd_max = -1;
985 for(vtty=vtty_list;vtty;vtty=vtty->next) {
986 if (!vtty->select_fd)
987 continue;
988
989 if ((fd = *vtty->select_fd) < 0)
990 continue;
991
992 if (fd > fd_max) fd_max = fd;
993 FD_SET(fd,&rfds);
994 }
995 VTTY_LIST_UNLOCK();
996
997 /* Wait for incoming data */
998 tv.tv_sec = 0;
999 tv.tv_usec = 50 * 1000; /* 50 ms */
1000 res = select(fd_max+1,&rfds,NULL,NULL,&tv);
1001
1002 if (res == -1) {
1003 if (errno != EINTR) {
1004 perror("vtty_thread: select");
1005
1006 for(vtty=vtty_list;vtty;vtty=vtty->next) {
1007 fprintf(stderr," %-15s: %s, FD %d\n",
1008 vtty->vm->name,vtty->name,vtty->fd);
1009 }
1010 }
1011 continue;
1012 }
1013
1014 /* Examine active FDs and call user handlers */
1015 VTTY_LIST_LOCK();
1016 for(vtty=vtty_list;vtty;vtty=vtty->next) {
1017 if (!vtty->select_fd)
1018 continue;
1019
1020 if ((fd = *vtty->select_fd) < 0)
1021 continue;
1022
1023 if (FD_ISSET(fd,&rfds)) {
1024 vtty_read_and_store(vtty);
1025 vtty->input_pending = TRUE;
1026 }
1027
1028 if (vtty->input_pending) {
1029 if (vtty->read_notifier != NULL)
1030 vtty->read_notifier(vtty);
1031
1032 vtty->input_pending = FALSE;
1033 }
1034
1035 /* Flush any pending output */
1036 if (!vtty->managed_flush)
1037 vtty_flush(vtty);
1038 }
1039 VTTY_LIST_UNLOCK();
1040 }
1041
1042 return NULL;
1043 }
1044
1045 /* Initialize the VTTY thread */
1046 int vtty_init(void)
1047 {
1048 if (pthread_create(&vtty_thread,NULL,vtty_thread_main,NULL)) {
1049 perror("vtty: pthread_create");
1050 return(-1);
1051 }
1052
1053 return(0);
1054 }

  ViewVC Help
Powered by ViewVC 1.1.26