/[dynamips]/trunk/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 /trunk/dev_vtty.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 12 - (hide annotations)
Sat Oct 6 16:45:40 2007 UTC (16 years, 6 months ago) by dpavlin
File MIME type: text/plain
File size: 28273 byte(s)
make working copy

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 dpavlin 11 vm_slot_show_all_info(vm);
694 dpavlin 2 break;
695 dpavlin 1
696     /* Dump the MIPS registers */
697     case 'r':
698 dpavlin 7 if (cpu0) cpu0->reg_dump(cpu0);
699 dpavlin 1 break;
700 dpavlin 7
701 dpavlin 1 /* Dump the latest memory accesses */
702     case 'm':
703     if (cpu0) memlog_dump(cpu0);
704 dpavlin 7 break;
705    
706 dpavlin 1 /* Suspend CPU emulation */
707     case 's':
708     vm_suspend(vm);
709     break;
710    
711     /* Resume CPU emulation */
712     case 'u':
713     vm_resume(vm);
714     break;
715    
716 dpavlin 7 /* Dump the MMU information */
717 dpavlin 1 case 't':
718 dpavlin 7 if (cpu0) cpu0->mmu_dump(cpu0);
719 dpavlin 1 break;
720    
721 dpavlin 7 /* Dump the MMU information (raw mode) */
722 dpavlin 4 case 'z':
723 dpavlin 7 if (cpu0) cpu0->mmu_raw_dump(cpu0);
724 dpavlin 4 break;
725 dpavlin 7
726     /* Memory translation cache statistics */
727 dpavlin 1 case 'l':
728 dpavlin 7 if (cpu0) cpu0->mts_show_stats(cpu0);
729 dpavlin 1 break;
730 dpavlin 7
731 dpavlin 1 /* Extract the configuration from the NVRAM */
732     case 'c':
733     vm_ios_save_config(vm);
734     break;
735    
736     /* Determine an idle pointer counter */
737     case 'i':
738 dpavlin 7 if (cpu0)
739     cpu0->get_idling_pc(cpu0);
740 dpavlin 1 break;
741    
742     /* Experimentations / Tests */
743     case 'x':
744     if (cpu0) {
745     /* IRQ triggering */
746 dpavlin 11 //vm_set_irq(vm,5);
747    
748     CPU_MIPS64(cpu0)->irq_disable = TRUE;
749 dpavlin 1 }
750     break;
751 dpavlin 4
752 dpavlin 7 case 'y':
753     if (cpu0) {
754     /* IRQ clearing */
755 dpavlin 11 vm_clear_irq(vm,5);
756 dpavlin 7 }
757     break;
758    
759 dpavlin 1 /* Twice Ctrl + ']' (0x1d, 29), or Alt-Gr + '*' (0xb3, 179) */
760     case 0x1d:
761     case 0xb3:
762     vtty_store(vtty,c);
763     break;
764    
765     default:
766     printf("\n\nInstance %s (ID %d)\n\n",vm->name,vm->instance_id);
767    
768     printf("o - Show the VM object list\n"
769     "d - Show the device list\n"
770 dpavlin 7 "r - Dump CPU registers\n"
771     "t - Dump MMU information\n"
772     "z - Dump MMU information (raw mode)\n"
773 dpavlin 1 "m - Dump the latest memory accesses\n"
774     "s - Suspend CPU emulation\n"
775     "u - Resume CPU emulation\n"
776     "q - Quit the emulator\n"
777     "k - Reboot the virtual machine\n"
778     "b - Show info about JIT compiled pages\n"
779 dpavlin 7 "l - MTS cache statistics\n"
780 dpavlin 1 "c - Write IOS configuration to disk\n"
781     "j - Non-JIT mode statistics\n"
782     "i - Determine an idling pointer counter\n"
783     "x - Experimentations (can crash the box!)\n"
784     "^] - Send ^]\n"
785     "Other - This help\n");
786     }
787     }
788    
789    
790     /* Read a character (until one is available) and store it in buffer */
791     static void vtty_read_and_store(vtty_t *vtty)
792     {
793     int c;
794    
795     /* wait until we get a character input */
796     c = vtty_read(vtty);
797    
798     /* if read error, do nothing */
799     if (c < 0) return;
800    
801     if (!vtty->terminal_support) {
802     vtty_store(vtty,c);
803     return;
804     }
805    
806     switch(vtty->input_state) {
807     case VTTY_INPUT_TEXT :
808     switch(c) {
809     case 0x1b:
810     vtty->input_state = VTTY_INPUT_VT1;
811     return;
812    
813     /* Ctrl + ']' (0x1d, 29), or Alt-Gr + '*' (0xb3, 179) */
814     case 0x1d:
815     case 0xb3:
816     vtty->input_state = VTTY_INPUT_REMOTE;
817     return;
818     case IAC :
819     vtty->input_state = VTTY_INPUT_TELNET;
820     return;
821     case 0: /* NULL - Must be ignored - generated by Linux telnet */
822     case 10: /* LF (Line Feed) - Must be ignored on Windows platform */
823     return;
824     default:
825     /* Store a standard character */
826     vtty_store(vtty,c);
827     return;
828     }
829    
830     case VTTY_INPUT_VT1 :
831     switch(c) {
832     case 0x5b:
833     vtty->input_state = VTTY_INPUT_VT2;
834     return;
835     default:
836     vtty_store(vtty,0x1b);
837     vtty_store(vtty,c);
838     }
839     vtty->input_state = VTTY_INPUT_TEXT;
840     return;
841    
842     case VTTY_INPUT_VT2 :
843     switch(c) {
844     case 0x41: /* Up Arrow */
845     vtty_store(vtty,16);
846     break;
847     case 0x42: /* Down Arrow */
848     vtty_store(vtty,14);
849     break;
850     case 0x43: /* Right Arrow */
851     vtty_store(vtty,6);
852     break;
853     case 0x44: /* Left Arrow */
854     vtty_store(vtty,2);
855     break;
856     default:
857     vtty_store(vtty,0x5b);
858     vtty_store(vtty,0x1b);
859     vtty_store(vtty,c);
860     break;
861     }
862     vtty->input_state = VTTY_INPUT_TEXT;
863     return;
864    
865     case VTTY_INPUT_REMOTE :
866     remote_control(vtty, c);
867     vtty->input_state = VTTY_INPUT_TEXT;
868     return;
869    
870     case VTTY_INPUT_TELNET :
871     vtty->telnet_cmd = c;
872     switch(c) {
873     case WILL:
874     case WONT:
875     case DO:
876     case DONT:
877     vtty->input_state = VTTY_INPUT_TELNET_IYOU;
878     return;
879     case SB :
880     vtty->telnet_cmd = c;
881     vtty->input_state = VTTY_INPUT_TELNET_SB1;
882     return;
883     case SE:
884     break;
885     case IAC :
886     vtty_store(vtty, IAC);
887     break;
888     }
889     vtty->input_state = VTTY_INPUT_TEXT;
890     return;
891    
892     case VTTY_INPUT_TELNET_IYOU :
893     vtty->telnet_opt = c;
894     /* if telnet client can support ttype, ask it to send ttype string */
895     if ((vtty->telnet_cmd == WILL) &&
896     (vtty->telnet_opt == TELOPT_TTYPE))
897     {
898     vtty_put_char(vtty, IAC);
899     vtty_put_char(vtty, SB);
900     vtty_put_char(vtty, TELOPT_TTYPE);
901     vtty_put_char(vtty, TELQUAL_SEND);
902     vtty_put_char(vtty, IAC);
903     vtty_put_char(vtty, SE);
904     }
905     vtty->input_state = VTTY_INPUT_TEXT;
906     return;
907    
908     case VTTY_INPUT_TELNET_SB1 :
909     vtty->telnet_opt = c;
910     vtty->input_state = VTTY_INPUT_TELNET_SB2;
911     return;
912    
913     case VTTY_INPUT_TELNET_SB2 :
914     vtty->telnet_qual = c;
915     if ((vtty->telnet_opt == TELOPT_TTYPE) &&
916     (vtty->telnet_qual == TELQUAL_IS))
917     vtty->input_state = VTTY_INPUT_TELNET_SB_TTYPE;
918     else
919     vtty->input_state = VTTY_INPUT_TELNET_NEXT;
920     return;
921    
922     case VTTY_INPUT_TELNET_SB_TTYPE :
923     /* parse ttype string: first char is sufficient */
924     /* if client is xterm or vt, set the title bar */
925     if ((c == 'x') || (c == 'X') || (c == 'v') || (c == 'V')) {
926     fprintf(vtty->fstream, "\033]0;Dynamips(%i): %s, %s\07",
927     vtty->vm->instance_id, vtty->vm->name, vtty->name);
928     }
929     vtty->input_state = VTTY_INPUT_TELNET_NEXT;
930     return;
931    
932     case VTTY_INPUT_TELNET_NEXT :
933     /* ignore all chars until next IAC */
934     if (c == IAC)
935     vtty->input_state = VTTY_INPUT_TELNET;
936     return;
937     }
938     }
939    
940     /* Read a character from the buffer (-1 if the buffer is empty) */
941     int vtty_get_char(vtty_t *vtty)
942     {
943     u_char c;
944    
945     VTTY_LOCK(vtty);
946    
947     if (vtty->read_ptr == vtty->write_ptr) {
948     VTTY_UNLOCK(vtty);
949     return(-1);
950     }
951    
952     c = vtty->buffer[vtty->read_ptr++];
953    
954     if (vtty->read_ptr == VTTY_BUFFER_SIZE)
955     vtty->read_ptr = 0;
956    
957     VTTY_UNLOCK(vtty);
958     return(c);
959     }
960    
961     /* Returns TRUE if a character is available in buffer */
962     int vtty_is_char_avail(vtty_t *vtty)
963     {
964     int res;
965    
966     VTTY_LOCK(vtty);
967     res = (vtty->read_ptr != vtty->write_ptr);
968     VTTY_UNLOCK(vtty);
969     return(res);
970     }
971    
972 dpavlin 7 /* Put char to vtty */
973 dpavlin 1 void vtty_put_char(vtty_t *vtty, char ch)
974     {
975     switch(vtty->type) {
976     case VTTY_TYPE_NONE:
977     break;
978    
979     case VTTY_TYPE_TERM:
980     fwrite(&ch, 1, 1, vtty->fstream);
981     break;
982    
983     case VTTY_TYPE_TCP:
984     if ((vtty->state == VTTY_STATE_TCP_RUNNING) &&
985     (fwrite(&ch, 1, 1, vtty->fstream) != 1))
986     {
987     vm_log(vtty->vm,"VTTY","%s: put char %d failed (%s)\n",
988     vtty->name,(int)ch,strerror(errno));
989     }
990     break;
991    
992     case VTTY_TYPE_SERIAL:
993     if (write(vtty->fd,&ch,1) != 1) {
994     vm_log(vtty->vm,"VTTY","%s: put char 0x%x failed (%s)\n",
995     vtty->name,(int)ch,strerror(errno));
996     }
997     break;
998    
999     default:
1000     fprintf(stderr,"vtty_put_char: bad vtty type %d\n",vtty->type);
1001     exit(1);
1002     }
1003     }
1004    
1005 dpavlin 7 /* Put a buffer to vtty */
1006     void vtty_put_buffer(vtty_t *vtty,char *buf,size_t len)
1007     {
1008     size_t i;
1009    
1010     for(i=0;i<len;i++)
1011     vtty_put_char(vtty,buf[i]);
1012     }
1013    
1014 dpavlin 1 /* Flush VTTY output */
1015     void vtty_flush(vtty_t *vtty)
1016     {
1017     switch(vtty->type) {
1018     case VTTY_TYPE_TERM:
1019     case VTTY_TYPE_TCP:
1020 dpavlin 11 if (vtty->fstream != NULL)
1021 dpavlin 1 fflush(vtty->fstream);
1022     break;
1023    
1024     case VTTY_TYPE_SERIAL:
1025 dpavlin 11 if (vtty->fd != -1)
1026     fsync(vtty->fd);
1027 dpavlin 1 break;
1028     }
1029     }
1030    
1031     /* VTTY thread */
1032     static void *vtty_thread_main(void *arg)
1033     {
1034     vtty_t *vtty;
1035     struct timeval tv;
1036     int fd,fd_max,res;
1037     fd_set rfds;
1038    
1039     for(;;) {
1040     VTTY_LIST_LOCK();
1041    
1042     /* Build the FD set */
1043     FD_ZERO(&rfds);
1044     fd_max = -1;
1045     for(vtty=vtty_list;vtty;vtty=vtty->next) {
1046     if (!vtty->select_fd)
1047     continue;
1048    
1049     if ((fd = *vtty->select_fd) < 0)
1050     continue;
1051    
1052     if (fd > fd_max) fd_max = fd;
1053     FD_SET(fd,&rfds);
1054     }
1055     VTTY_LIST_UNLOCK();
1056    
1057     /* Wait for incoming data */
1058     tv.tv_sec = 0;
1059     tv.tv_usec = 50 * 1000; /* 50 ms */
1060     res = select(fd_max+1,&rfds,NULL,NULL,&tv);
1061    
1062     if (res == -1) {
1063     if (errno != EINTR) {
1064     perror("vtty_thread: select");
1065    
1066     for(vtty=vtty_list;vtty;vtty=vtty->next) {
1067     fprintf(stderr," %-15s: %s, FD %d\n",
1068     vtty->vm->name,vtty->name,vtty->fd);
1069     }
1070     }
1071     continue;
1072     }
1073    
1074     /* Examine active FDs and call user handlers */
1075     VTTY_LIST_LOCK();
1076     for(vtty=vtty_list;vtty;vtty=vtty->next) {
1077     if (!vtty->select_fd)
1078     continue;
1079    
1080     if ((fd = *vtty->select_fd) < 0)
1081     continue;
1082    
1083     if (FD_ISSET(fd,&rfds)) {
1084     vtty_read_and_store(vtty);
1085 dpavlin 4 vtty->input_pending = TRUE;
1086     }
1087 dpavlin 1
1088 dpavlin 4 if (vtty->input_pending) {
1089 dpavlin 1 if (vtty->read_notifier != NULL)
1090 dpavlin 4 vtty->read_notifier(vtty);
1091    
1092     vtty->input_pending = FALSE;
1093 dpavlin 1 }
1094    
1095     /* Flush any pending output */
1096     if (!vtty->managed_flush)
1097     vtty_flush(vtty);
1098     }
1099     VTTY_LIST_UNLOCK();
1100     }
1101    
1102     return NULL;
1103     }
1104    
1105     /* Initialize the VTTY thread */
1106     int vtty_init(void)
1107     {
1108     if (pthread_create(&vtty_thread,NULL,vtty_thread_main,NULL)) {
1109     perror("vtty: pthread_create");
1110     return(-1);
1111     }
1112    
1113     return(0);
1114     }

  ViewVC Help
Powered by ViewVC 1.1.26