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.


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