/[dynamips]/upstream/dynamips-0.2.7-RC1/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

Annotation of /upstream/dynamips-0.2.7-RC1/dev_vtty.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 7 - (hide annotations)
Sat Oct 6 16:23:47 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 28825 byte(s)
dynamips-0.2.7-RC1

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

  ViewVC Help
Powered by ViewVC 1.1.26