Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


9419804e1f225393926d0c84e763428ba116a683
[palacios.git] / linux_usr / v3_cons_sc.c
1 /* 
2  * V3 Console utility
3  * Taken from Palacios console display in MINIX ( by Erik Van der Kouwe )
4  * (c) Jack lange, 2010
5  * (c) Peter Dinda, 2011 (Scan code encoding)
6  */
7
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/ioctl.h> 
12 #include <errno.h>
13 #include <assert.h>
14 #include <string.h>
15 #include <fcntl.h>
16 #include <unistd.h>
17 #include <curses.h>
18 #include <termios.h>
19 #include <linux/kd.h>
20 #include <linux/keyboard.h>
21
22 #include "v3_ctrl.h"
23
24 static int use_curses = 0;
25 static int debug_enable = 0;
26
27
28 typedef enum { CONSOLE_CURS_SET = 1,
29                CONSOLE_CHAR_SET = 2,
30                CONSOLE_SCROLL = 3,
31                CONSOLE_UPDATE = 4,
32                CONSOLE_RESOLUTION = 5 } console_op_t;
33
34
35
36 static struct {
37     WINDOW * win;
38     int x;
39     int y;
40     int rows;
41     int cols;
42     struct termios termios_old;
43     unsigned char old_kbd_mode;
44 } console;
45
46
47 struct cursor_msg {
48     int x;
49     int y;
50 } __attribute__((packed));
51
52 struct character_msg {
53     int x;
54     int y;
55     char c;
56     unsigned char style;
57 } __attribute__((packed));
58
59 struct scroll_msg {
60     int lines;
61 } __attribute__((packed));
62
63 struct resolution_msg {
64     int cols;
65     int rows;
66 } __attribute__((packed));
67
68
69 struct cons_msg {
70     unsigned char op;
71     union {
72         struct cursor_msg cursor;
73         struct character_msg  character;
74         struct scroll_msg scroll;
75         struct resolution_msg resolution;
76     };
77 } __attribute__((packed)); 
78
79
80
81
82 static int handle_char_set(struct character_msg * msg) {
83     char c = msg->c;
84
85     if (debug_enable) {
86         fprintf(stderr, "setting char (%c), at (x=%d, y=%d)\n", c, msg->x, msg->y);
87     }
88
89     if (c == 0) {
90         c = ' ';
91     }
92
93
94     if ((c < ' ') || (c >= 127)) {
95         if (debug_enable) { 
96             fprintf(stderr, "unexpected control character %d\n", c);
97         }
98         c = '?';
99     }
100
101     if (use_curses) {
102         /* clip whatever falls outside the visible area to avoid errors */
103         if ((msg->x < 0) || (msg->y < 0) ||
104             (msg->x > console.win->_maxx) || 
105             (msg->y > console.win->_maxy)) {
106
107             if (debug_enable) { 
108                 fprintf(stderr, "Char out of range (x=%d,y=%d) MAX:(x=%d,y=%d)\n",
109                         msg->x, msg->y, console.win->_maxx, console.win->_maxy);
110             }
111
112             return -1;
113         }
114
115         if ((msg->x == console.win->_maxx) &&
116             (msg->y == console.win->_maxy)) {
117             return -1;
118         }
119
120         wattron(console.win, COLOR_PAIR(msg->style));
121         mvwaddch(console.win, msg->y, msg->x, c);
122         wattroff(console.win, COLOR_PAIR(msg->style));
123
124     } else {
125         //stdout text display
126         while (console.y < msg->y) {
127             printf("\n");
128             console.x = 0;
129             console.y++;
130         }
131
132         while (console.x < msg->x) {
133             printf(" ");
134             console.x++;
135         }
136
137         printf("%c", c);
138         console.x++;
139
140         assert(console.x <= console.cols); 
141
142         if (console.x == console.cols) {
143             printf("\n");
144             console.x = 0;
145             console.y++;
146         }
147     }
148
149     return 0;
150 }
151
152 int handle_curs_set(struct cursor_msg * msg) {
153     if (debug_enable) {
154         fprintf(stderr, "cursor set: (x=%d, y=%d)\n", msg->x, msg->y);
155     }
156
157     if (use_curses) {
158         /* nothing to do now, cursor is set before update to make sure it isn't 
159          * affected by character_set
160          */
161
162         console.x = msg->x;
163         console.y = msg->y;
164     }
165     
166     return 0;
167 }
168
169
170 int handle_scroll(struct scroll_msg * msg) {
171     int lines = msg->lines;
172
173     if (debug_enable) {
174         fprintf(stderr, "scroll: %d lines\n", lines);
175     }
176
177
178     assert(lines >= 0);
179
180     if (use_curses) {
181         while (lines > 0) {
182             scroll(console.win);
183             lines--;
184         }
185     } else {
186         console.y -= lines;     
187     }
188 }
189
190 int handle_text_resolution(struct resolution_msg * msg) {
191     if (debug_enable) {
192         fprintf(stderr, "text resolution: rows=%d, cols=%d\n", msg->rows, msg->cols);
193     }
194
195
196     console.rows = msg->rows;
197     console.cols = msg->cols;
198
199     return 0;
200 }
201
202 int handle_update( void ) {
203     if (debug_enable) {
204         fprintf(stderr, "update\n");
205     }    
206
207     if (use_curses) {
208
209         if ( (console.x >= 0) && (console.y >= 0) &&
210              (console.x <= console.win->_maxx) &&
211              (console.y <= console.win->_maxy) ) {
212
213             wmove(console.win, console.y, console.x);
214
215         }
216
217         wrefresh(console.win);
218     } else {
219         fflush(stdout);
220     }
221 }
222
223
224 int handle_console_msg(int cons_fd) {
225     int ret = 0;
226     struct cons_msg msg;
227
228     ret = read(cons_fd, &msg, sizeof(struct cons_msg));
229
230     switch (msg.op) {
231         case CONSOLE_CURS_SET:
232             //      printf("Console cursor set (x=%d, y=%d)\n", msg.cursor.x, msg.cursor.y);
233             handle_curs_set(&(msg.cursor));
234             break;
235         case CONSOLE_CHAR_SET:
236             handle_char_set(&(msg.character));
237             /*      printf("Console character set (x=%d, y=%d, c=%c, style=%c)\n", 
238               msg.character.x, msg.character.y, msg.character.c, msg.character.style);*/
239             break;
240         case CONSOLE_SCROLL:
241             //  printf("Console scroll (lines=%d)\n", msg.scroll.lines);
242             handle_scroll(&(msg.scroll));
243             break;
244         case CONSOLE_UPDATE:
245             // printf("Console update\n");
246             handle_update();
247             break;
248         case CONSOLE_RESOLUTION:
249             handle_text_resolution(&(msg.resolution));
250             break;
251         default:
252             printf("Invalid console message operation (%d)\n", msg.op);
253             break;
254     }
255
256     return 0;
257 }
258
259
260 int send_key(int cons_fd, char scan_code) {
261
262     return 0;
263 }
264
265
266
267 void handle_exit(void) {
268     if ( debug_enable ) {
269         fprintf(stderr, "Exiting from console terminal\n");
270     }
271
272     if (use_curses) {
273         endwin();
274     }
275
276     //    tcsetattr(STDIN_FILENO, TCSANOW, &console.termios_old);
277
278     // ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE);
279 }
280
281
282 #define NO_KEY { 0, 0 }
283
284 struct key_code {
285     unsigned char scan_code;
286     unsigned char capital;
287 };
288
289 static const struct key_code ascii_to_key_code[] = {             // ASCII Value Serves as Index
290     NO_KEY,         NO_KEY,         {0x50, 0},         {0x48, 0},      // 0x00 - 0x03
291     {0x4B, 0},         {0x4D, 0},         NO_KEY,         { 0x0E, 0 }, // 0x04 - 0x07
292     { 0x0E, 0 },    { 0x0F, 0 },    { 0x1C, 0 },    NO_KEY,      // 0x08 - 0x0B
293     NO_KEY,         { 0x1C, 0 },    NO_KEY,         NO_KEY,      // 0x0C - 0x0F
294     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x10 - 0x13
295     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x14 - 0x17
296     NO_KEY,         NO_KEY,         NO_KEY,         { 0x01, 0 }, // 0x18 - 0x1B
297     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x1C - 0x1F
298     { 0x39, 0 },    { 0x02, 1 },    { 0x28, 1 },    { 0x04, 1 }, // 0x20 - 0x23
299     { 0x05, 1 },    { 0x06, 1 },    { 0x08, 1 },    { 0x28, 0 }, // 0x24 - 0x27
300     { 0x0A, 1 },    { 0x0B, 1 },    { 0x09, 1 },    { 0x0D, 1 }, // 0x28 - 0x2B
301     { 0x33, 0 },    { 0x0C, 0 },    { 0x34, 0 },    { 0x35, 0 }, // 0x2C - 0x2F
302     { 0x0B, 0 },    { 0x02, 0 },    { 0x03, 0 },    { 0x04, 0 }, // 0x30 - 0x33
303     { 0x05, 0 },    { 0x06, 0 },    { 0x07, 0 },    { 0x08, 0 }, // 0x34 - 0x37
304     { 0x09, 0 },    { 0x0A, 0 },    { 0x27, 1 },    { 0x27, 0 }, // 0x38 - 0x3B
305     { 0x33, 1 },    { 0x0D, 0 },    { 0x34, 1 },    { 0x35, 1 }, // 0x3C - 0x3F
306     { 0x03, 1 },    { 0x1E, 1 },    { 0x30, 1 },    { 0x2E, 1 }, // 0x40 - 0x43
307     { 0x20, 1 },    { 0x12, 1 },    { 0x21, 1 },    { 0x22, 1 }, // 0x44 - 0x47
308     { 0x23, 1 },    { 0x17, 1 },    { 0x24, 1 },    { 0x25, 1 }, // 0x48 - 0x4B
309     { 0x26, 1 },    { 0x32, 1 },    { 0x31, 1 },    { 0x18, 1 }, // 0x4C - 0x4F
310     { 0x19, 1 },    { 0x10, 1 },    { 0x13, 1 },    { 0x1F, 1 }, // 0x50 - 0x53
311     { 0x14, 1 },    { 0x16, 1 },    { 0x2F, 1 },    { 0x11, 1 }, // 0x54 - 0x57
312     { 0x2D, 1 },    { 0x15, 1 },    { 0x2C, 1 },    { 0x1A, 0 }, // 0x58 - 0x5B
313     { 0x2B, 0 },    { 0x1B, 0 },    { 0x07, 1 },    { 0x0C, 1 }, // 0x5C - 0x5F
314     { 0x29, 0 },    { 0x1E, 0 },    { 0x30, 0 },    { 0x2E, 0 }, // 0x60 - 0x63
315     { 0x20, 0 },    { 0x12, 0 },    { 0x21, 0 },    { 0x22, 0 }, // 0x64 - 0x67
316     { 0x23, 0 },    { 0x17, 0 },    { 0x24, 0 },    { 0x25, 0 }, // 0x68 - 0x6B
317     { 0x26, 0 },    { 0x32, 0 },    { 0x31, 0 },    { 0x18, 0 }, // 0x6C - 0x6F
318     { 0x19, 0 },    { 0x10, 0 },    { 0x13, 0 },    { 0x1F, 0 }, // 0x70 - 0x73
319     { 0x14, 0 },    { 0x16, 0 },    { 0x2F, 0 },    { 0x11, 0 }, // 0x74 - 0x77
320     { 0x2D, 0 },    { 0x15, 0 },    { 0x2C, 0 },    { 0x1A, 1 }, // 0x78 - 0x7B
321     { 0x2B, 1 },    { 0x1B, 1 },    { 0x29, 1 },    { 0x0E, 0 }  // 0x7C - 0x7F
322 };
323
324
325
326 #define writeit(fd,c)  do { if (debug_enable) { fprintf(stderr,"scancode 0x%x\n",(c));} if (write((fd),&(c),1)!=1) { return -1; } } while (0)
327
328 int send_char_to_palacios_as_scancodes(int fd, unsigned char c)
329 {
330     unsigned char sc;
331
332     if (debug_enable) {
333         fprintf(stderr,"key '%c'\n",c);
334     }
335
336     if (c<0x80) { 
337         struct key_code k = ascii_to_key_code[c];
338         
339         if (k.scan_code==0 && k.capital==0) { 
340             if (debug_enable) { 
341                 fprintf(stderr,"Cannot send key '%c' to palacios as it maps to no scancode\n",c);
342             }
343         } else {
344             if (k.capital) { 
345                 //shift down
346                 sc = 0x2a ; // left shift down
347                 writeit(fd,sc);
348             }
349             
350             
351             sc = k.scan_code;
352             
353             writeit(fd,sc);  // key down
354             
355             sc |= 0x80;      // key up
356             
357             writeit(fd,sc);
358             
359             if (k.capital) { 
360                 sc = 0x2a | 0x80;
361                 writeit(fd,sc);
362             }
363         }
364             
365     } else {
366
367         
368         if (debug_enable) { 
369             fprintf(stderr,"Cannot send key '%c' to palacios because it is >=0x80\n",c);
370         }
371
372         
373     }
374     return 0;
375 }
376
377
378 #define MIN_TTY_COLS  80
379 #define MIN_TTY_ROWS  25
380 int check_terminal_size (void)
381 {
382     unsigned short n_cols = 0;
383     unsigned short n_rows = 0;
384     struct winsize winsz; 
385
386     ioctl (fileno(stdin), TIOCGWINSZ, &winsz);
387     n_cols = winsz.ws_col;
388     n_rows = winsz.ws_row;
389
390     if (n_cols < MIN_TTY_COLS || n_rows < MIN_TTY_ROWS) {
391         printf ("Your window is not large enough.\n");
392         printf ("It must be at least %dx%d, but yours is %dx%d\n",
393                 MIN_TTY_COLS, MIN_TTY_ROWS, n_cols, n_rows);
394     return (-1);
395     }
396
397     /* SUCCESS */
398     return (0);
399 }
400
401
402
403 static void
404 init_colors (void)
405 {
406     start_color();
407     int i;
408     for (i = 0; i < 0x100; i++) {
409         init_pair(i, i & 0xf, (i >> 4) & 0xf);
410     }
411 }
412
413
414 int main(int argc, char* argv[]) {
415     int vm_fd;
416     int cons_fd;
417     char * vm_dev = NULL;
418     struct termios termios;
419
420     use_curses = 1;
421
422     if (argc < 2) {
423         printf("usage: v3_cons_sc <vm_device>\n");
424         return -1;
425     }
426
427     /* Check for minimum Terminal size at start */
428     if (0 != check_terminal_size()) {
429         printf ("Error: terminal too small!\n");
430         return -1;
431     }
432
433     vm_dev = argv[1];
434
435     vm_fd = open(vm_dev, O_RDONLY);
436
437     if (vm_fd == -1) {
438         printf("Error opening VM device: %s\n", vm_dev);
439         return -1;
440     }
441
442     cons_fd = ioctl(vm_fd, V3_VM_CONSOLE_CONNECT, NULL); 
443
444     /* Close the file descriptor.  */ 
445     close(vm_fd); 
446
447     if (cons_fd < 0) {
448         printf("Error opening stream Console\n");
449         return -1;
450     }
451
452     tcgetattr(STDIN_FILENO, &console.termios_old);
453     atexit(handle_exit);
454
455     console.x = 0;
456     console.y = 0;
457
458
459     if (use_curses) {
460         gettmode();
461         console.win = initscr();
462         
463         if (console.win == NULL) {
464             fprintf(stderr, "Error initialization curses screen\n");
465             exit(-1);
466         }
467
468         scrollok(console.win, 1);
469
470         erase();
471     init_colors();
472     }
473
474     /*
475     termios = console.termios_old;
476     termios.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR);
477     termios.c_iflag &= ~(INLCR | INPCK | ISTRIP | IXOFF | IXON | PARMRK); 
478     //termios.c_iflag &= ~(ICRNL | INLCR );    
479
480     //  termios.c_iflag |= SCANCODES; 
481     //    termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL); 
482     //termios.c_lflag &= ~(ICANON | IEXTEN | ISIG | NOFLSH);
483     termios.c_lflag &= ~(ICANON | ECHO);
484
485     termios.c_cc[VMIN] = 1;
486     termios.c_cc[VTIME] = 0;
487
488     tcflush(STDIN_FILENO, TCIFLUSH);
489     tcsetattr(STDIN_FILENO, TCSANOW, &termios);
490     */    
491
492     raw();
493     cbreak();
494     noecho();
495     keypad(console.win, TRUE);
496
497     //ioctl(STDIN_FILENO, KDSKBMODE, K_RAW);
498
499     while (1) {
500         int ret; 
501         int bytes_read = 0;
502         fd_set rset;
503
504         FD_ZERO(&rset);
505         FD_SET(cons_fd, &rset);
506         FD_SET(STDIN_FILENO, &rset);
507
508         ret = select(cons_fd + 1, &rset, NULL, NULL, NULL);
509         
510         //      printf("Returned from select...\n");
511
512         if (ret == 0) {
513             continue;
514         } else if (ret == -1) {
515             perror("Select returned error...\n");
516             return -1;
517         }
518
519         if (FD_ISSET(cons_fd, &rset)) {
520             if (handle_console_msg(cons_fd) == -1) {
521                 printf("Console Error\n");
522                 return -1;
523             }
524         }
525
526     if (FD_ISSET(STDIN_FILENO, &rset)) {
527         unsigned char key = getch();
528
529         if (key == '\\') { // ESC
530             break;
531         } else if (key == '`') {
532             unsigned char sc = 0x44; // F10
533             writeit(cons_fd,sc);
534             sc |= 0x80;
535             writeit(cons_fd,sc);
536         } else if (key == '~') {  // CTRL-C 
537             unsigned char sc;
538             sc = 0x1d;  // left ctrl down
539             writeit(cons_fd,sc);
540             sc = 0x2e; // c down
541             writeit(cons_fd,sc);
542             sc = 0x2e | 0x80;   // c up
543             writeit(cons_fd,sc);
544             sc = 0x1d | 0x80;   // left ctrl up
545             writeit(cons_fd,sc);
546         } else {
547             if (send_char_to_palacios_as_scancodes(cons_fd,key)) {
548                 printf("Error sending key to console\n");
549                 return -1;
550             }
551         }
552             
553         }
554     } 
555
556     erase();
557
558     printf("Console terminated\n");
559
560     close(cons_fd);
561
562     return 0; 
563 }
564
565