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.


30e07d1f22ecfbf804916b7dab5c9a90f0adf7bb
[palacios.git] / palacios / src / devices / telnet_cons.c
1 /* 
2  * This file is part of the Palacios Virtual Machine Monitor developed
3  * by the V3VEE Project with funding from the United States National 
4  * Science Foundation and the Department of Energy.  
5  *
6  * The V3VEE Project is a joint project between Northwestern University
7  * and the University of New Mexico.  You can find out more at 
8  * http://www.v3vee.org
9  *
10  * Copyright (c) 2009, Robert Deloatch <rtdeloatch@gmail.com>
11  * Copyright (c) 2009, Steven Jaconette <stevenjaconette2007@u.northwestern.edu> 
12  * Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org> 
13  * All rights reserved.
14  *
15  * Author: Robdert Deloatch <rtdeloatch@gmail.com>
16  *         Steven Jaconette <stevenjaconette2007@u.northwestern.edu>
17  *
18  * This is free software.  You are permitted to use,
19  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20  */
21
22 /* Interface between virtual video card and client apps */
23
24 #include <palacios/vmm.h>
25 #include <palacios/vmm_dev_mgr.h>
26 #include <palacios/vmm_sprintf.h>
27 #include <palacios/vmm_host_events.h>
28 #include <palacios/vmm_lock.h>
29 #include <palacios/vmm_string.h>
30 #include <palacios/vmm_socket.h>
31
32 #include <devices/cga.h>
33 #include <devices/telnet_cons.h>
34
35 #define NUM_ROWS 25
36 #define NUM_COLS 80
37 #define BYTES_PER_ROW (NUM_COLS * 2)
38 #define BYTES_PER_COL 2
39
40
41 #define SCREEN_SIZE 4000
42
43 #define NO_KEY { 0, 0 }
44 #define ESC_CHAR  ((uint8_t)0x1b)
45 #define CR_CHAR   ((uint8_t)0x0d)
46
47 #define ASCII_CTRL_CODE 0x1d
48
49
50 struct cons_state {
51     int server_fd;
52     int client_fd;
53
54     uint16_t port;
55
56     int connected;
57
58     v3_lock_t cons_lock;
59
60     struct vm_device * frontend_dev;
61 };
62
63 struct key_code {
64     uint8_t scan_code;
65     uint8_t capital;
66 };
67
68
69 static const struct key_code ascii_to_key_code[] = {             // ASCII Value Serves as Index
70     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x00 - 0x03
71     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x04 - 0x07
72     { 0x0E, 0 },    { 0x0F, 0 },    { 0x1C, 0 },    NO_KEY,      // 0x08 - 0x0B
73     NO_KEY,         { 0x1C, 0 },    NO_KEY,         NO_KEY,      // 0x0C - 0x0F
74     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x10 - 0x13
75     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x14 - 0x17
76     NO_KEY,         NO_KEY,         NO_KEY,         { 0x01, 0 }, // 0x18 - 0x1B
77     NO_KEY,         NO_KEY,         NO_KEY,         NO_KEY,      // 0x1C - 0x1F
78     { 0x39, 0 },    { 0x02, 1 },    { 0x28, 1 },    { 0x04, 1 }, // 0x20 - 0x23
79     { 0x05, 1 },    { 0x06, 1 },    { 0x08, 1 },    { 0x28, 0 }, // 0x24 - 0x27
80     { 0x0A, 1 },    { 0x0B, 1 },    { 0x09, 1 },    { 0x0D, 1 }, // 0x28 - 0x2B
81     { 0x33, 0 },    { 0x0C, 0 },    { 0x34, 0 },    { 0x35, 0 }, // 0x2C - 0x2F
82     { 0x0B, 0 },    { 0x02, 0 },    { 0x03, 0 },    { 0x04, 0 }, // 0x30 - 0x33
83     { 0x05, 0 },    { 0x06, 0 },    { 0x07, 0 },    { 0x08, 0 }, // 0x34 - 0x37
84     { 0x09, 0 },    { 0x0A, 0 },    { 0x27, 1 },    { 0x27, 0 }, // 0x38 - 0x3B
85     { 0x33, 1 },    { 0x0D, 0 },    { 0x34, 1 },    { 0x35, 1 }, // 0x3C - 0x3F
86     { 0x03, 1 },    { 0x1E, 1 },    { 0x30, 1 },    { 0x2E, 1 }, // 0x40 - 0x43
87     { 0x20, 1 },    { 0x12, 1 },    { 0x21, 1 },    { 0x22, 1 }, // 0x44 - 0x47
88     { 0x23, 1 },    { 0x17, 1 },    { 0x24, 1 },    { 0x25, 1 }, // 0x48 - 0x4B
89     { 0x26, 1 },    { 0x32, 1 },    { 0x31, 1 },    { 0x18, 1 }, // 0x4C - 0x4F
90     { 0x19, 1 },    { 0x10, 1 },    { 0x13, 1 },    { 0x1F, 1 }, // 0x50 - 0x53
91     { 0x14, 1 },    { 0x16, 1 },    { 0x2F, 1 },    { 0x11, 1 }, // 0x54 - 0x57
92     { 0x2D, 1 },    { 0x15, 1 },    { 0x2C, 1 },    { 0x1A, 0 }, // 0x58 - 0x5B
93     { 0x2B, 0 },    { 0x1B, 0 },    { 0x07, 1 },    { 0x0C, 1 }, // 0x5C - 0x5F
94     { 0x29, 0 },    { 0x1E, 0 },    { 0x30, 0 },    { 0x2E, 0 }, // 0x60 - 0x63
95     { 0x20, 0 },    { 0x12, 0 },    { 0x21, 0 },    { 0x22, 0 }, // 0x64 - 0x67
96     { 0x23, 0 },    { 0x17, 0 },    { 0x24, 0 },    { 0x25, 0 }, // 0x68 - 0x6B
97     { 0x26, 0 },    { 0x32, 0 },    { 0x31, 0 },    { 0x18, 0 }, // 0x6C - 0x6F
98     { 0x19, 0 },    { 0x10, 0 },    { 0x13, 0 },    { 0x1F, 0 }, // 0x70 - 0x73
99     { 0x14, 0 },    { 0x16, 0 },    { 0x2F, 0 },    { 0x11, 0 }, // 0x74 - 0x77
100     { 0x2D, 0 },    { 0x15, 0 },    { 0x2C, 0 },    { 0x1A, 1 }, // 0x78 - 0x7B
101     { 0x2B, 1 },    { 0x1B, 1 },    { 0x29, 1 },    { 0x0E, 0 }  // 0x7C - 0x7F
102 };
103
104
105
106 static int deliver_scan_code(struct vm_device * dev, struct key_code * key) {
107     struct v3_keyboard_event key_event;
108     struct v3_keyboard_event key_shift;
109     uint_t cap = key->capital;
110
111     key_event.status = 0;
112     key_event.scan_code = (uint8_t)key->scan_code;
113
114     PrintDebug("Scan code: 0x%x\n", key_event.scan_code);
115
116
117     if (cap) {
118         key_shift.status = 0;
119         key_shift.scan_code = (uint8_t)0x2A;
120
121         if (v3_deliver_keyboard_event(dev->vm, &key_shift) == -1) {
122             PrintError("Video: Error delivering key event\n");
123             return -1;
124         }
125     }
126
127     // Press
128     if (v3_deliver_keyboard_event(dev->vm, &key_event) == -1) {
129         PrintError("Video: Error delivering key event\n");
130         return -1;
131     }
132
133     // Release
134     key_event.scan_code = key_event.scan_code | 0x80;
135   
136     if (v3_deliver_keyboard_event(dev->vm, &key_event) == -1) {
137         PrintError("Video: Error delivering key event\n");
138         return -1;
139     }
140
141
142     if (cap) {
143         key_shift.scan_code = 0x2A | 0x80;
144
145         if (v3_deliver_keyboard_event(dev->vm, &key_shift) == -1) {
146             PrintError("Video: Error delivering key event\n");
147             return -1;
148         }
149     }
150
151     PrintDebug("Finished with Key delivery\n");
152     return 0;
153 }
154
155
156
157
158 static int recv_all(int socket, char * buf, int length) {
159     int bytes_read = 0;
160     
161     PrintDebug("Reading %d bytes\n", length - bytes_read);
162     while (bytes_read < length) {
163         int tmp_bytes = V3_Recv(socket, buf + bytes_read, length - bytes_read);
164         PrintDebug("Received %d bytes\n", tmp_bytes);
165
166         if (tmp_bytes == 0) {
167             PrintError("Connection Closed unexpectedly\n");
168             return 0;
169         } else if (tmp_bytes == -1) {
170             PrintError("Socket Error in for V3_RECV\n");
171             return -1;
172         }
173
174         bytes_read += tmp_bytes;
175     }
176     
177     return bytes_read;
178 }
179
180
181 static int send_all(const int sock, const char * buf, const int len){
182     int bytes_left = len;
183
184     while (bytes_left != 0) {
185         int written = 0;
186
187         if ((written = V3_Send(sock, buf + (len - bytes_left), bytes_left)) == -1) {
188             return -1;
189         }
190
191         bytes_left -= written;
192     }
193     return 0;
194 }
195
196 // Translate attribute color into terminal escape sequence color
197 static const uint8_t fg_color_map[] = {
198     30, 34, 32, 36, 31, 35, 33, 37, 90, 94, 92, 96, 91, 95, 93, 97
199 };
200
201 static const uint8_t bg_color_map[] = {
202     40, 44, 42, 46, 41, 45, 43, 47, 100, 104, 102, 106, 101, 105, 103, 107
203 };
204
205
206 #define INT_TO_CHAR(index, buf, val)                                    \
207     do {                                                                \
208         uint8_t base = '0';                                             \
209         if ((val) >= 100) buf[(index)++] = base + ((val) / 100);        \
210         if ((val) >= 10)  buf[(index)++] = base + ((val) / 10);         \
211         buf[(index)++] = base + ((val) % 10);                           \
212     } while (0)
213
214
215 static int send_update(struct vm_device * dev, uint8_t  x, uint8_t  y, uint8_t attrib, uint8_t val) {
216     struct cons_state * state = (struct cons_state *)dev->private_data;
217     uint8_t fg_color = fg_color_map[(attrib & 0x0f) % 16];
218     uint8_t bg_color = bg_color_map[(attrib & 0xf0) % 16];
219     uint8_t buf[32];
220     int ret = 0;
221     int i = 0;
222
223     memset(buf, 0, 32);
224
225     buf[i++] = ESC_CHAR;
226     buf[i++] = '[';
227
228     INT_TO_CHAR(i, buf, y + 1);
229
230     buf[i++] = ';';
231
232     INT_TO_CHAR(i, buf, x + 1);
233
234     buf[i++] = 'H';
235     buf[i++] = ESC_CHAR;
236     buf[i++] = '[';
237     buf[i++] = '0';
238     buf[i++] = 'm';
239     buf[i++] = ESC_CHAR;
240     buf[i++] = '[';
241
242     INT_TO_CHAR(i, buf, fg_color);
243
244     buf[i++] = ';';
245
246     INT_TO_CHAR(i, buf, bg_color);
247
248     buf[i++] = 'm';
249
250     // Add value
251
252     buf[i++] = ESC_CHAR;
253     buf[i++] = '[';
254     INT_TO_CHAR(i, buf, y + 1);
255     buf[i++] = ';';
256     INT_TO_CHAR(i, buf, x + 1);
257     buf[i++] = 'H';
258     buf[i++] = val;
259
260     PrintDebug("printing value '%c'\n", val);
261
262     if (state->connected) {
263         uint64_t start, end;
264
265         rdtscll(start);
266         ret =  send_all(state->client_fd, buf, 32);
267         rdtscll(end);
268
269         PrintDebug("Sendall latency=%d cycles\n", (uint32_t)(end - start));
270     }
271
272     return ret;
273 }
274
275
276
277 static int cursor_update(uint_t x, uint_t y, void * private_data) {
278     struct vm_device * dev = (struct vm_device *)private_data;
279     struct cons_state * state = (struct cons_state *)dev->private_data;
280     uint8_t buf[16];
281     int ret = 0;
282     addr_t irq_state = 0;
283     int i = 0;
284
285     memset(buf, 0, 16);
286
287     buf[i++] = ESC_CHAR;
288     buf[i++] = '[';
289     INT_TO_CHAR(i, buf, y + 1);
290     buf[i++] = ';';
291     INT_TO_CHAR(i, buf, x + 1);
292     buf[i++] = 'H';
293
294
295     irq_state = v3_lock_irqsave(state->cons_lock);
296
297     if (state->connected) {
298         ret = send_all(state->client_fd, buf, 16);
299     }
300
301     v3_unlock_irqrestore(state->cons_lock, irq_state);
302     
303     return ret;
304 }
305
306
307 static int screen_update(uint_t x, uint_t y, uint_t length, void * private_data) {
308     struct vm_device * dev = (struct vm_device *)private_data;
309     struct cons_state * state = (struct cons_state *)dev->private_data;
310     uint_t offset = (x * BYTES_PER_COL) + (y * BYTES_PER_ROW);
311     uint8_t fb_buf[length];
312     int i = 0;
313     uint_t cur_x = x;
314     uint_t cur_y = y;
315     addr_t irq_state = 0;
316     int ret = 0;
317
318     memset(fb_buf, 0, length);
319     
320
321
322     irq_state = v3_lock_irqsave(state->cons_lock);
323
324     v3_cons_get_fb(state->frontend_dev, fb_buf, offset, length);
325
326     v3_unlock_irqrestore(state->cons_lock, irq_state);
327
328
329     for (i = 0; i < length; i += 2) {
330         uint_t col_index = i;
331         uint8_t col[2];
332
333         col[0] = fb_buf[col_index];     // Character
334         col[1] = fb_buf[col_index + 1]; // Attribute
335
336         irq_state = v3_lock_irqsave(state->cons_lock);
337
338         if (send_update(dev, cur_x, cur_y, col[1], col[0]) == -1) {
339             PrintError("Could not send attribute to telnet session\n");
340             ret = -1;
341             break;
342         }
343
344         v3_unlock_irqrestore(state->cons_lock, irq_state);
345                                     
346
347         // CAUTION: the order of these statements is critical
348         // cur_y depends on the previous value of cur_x
349         cur_y = cur_y + ((cur_x + 1) / NUM_COLS);
350         cur_x = (cur_x + 1) % NUM_COLS;
351     }
352
353
354     return ret;
355 }
356
357 static int scroll(uint_t rows, void * private_data) {
358     struct vm_device * dev = (struct vm_device *)private_data;
359     struct cons_state * state = (struct cons_state *)dev->private_data;
360     addr_t irq_state = 0;
361     int ret = 0;
362
363     if (rows > 0) {
364         int i = 0;
365
366         irq_state = v3_lock_irqsave(state->cons_lock);
367
368         for (i = rows; i > 0; i--) {
369             uint8_t message[2] = { ESC_CHAR, 'D' };
370
371             if (state->connected) {
372                 if (send_all(state->client_fd, message, sizeof(message)) == -1) {
373                     PrintError("Could not send scroll command\n");
374                     ret = -1;
375                     break;
376                 }
377             }
378         }
379         
380         v3_unlock_irqrestore(state->cons_lock, irq_state);
381
382     } else if (rows < 0) {
383         ret = screen_update(0, 0, SCREEN_SIZE, private_data);
384     }
385
386     return ret;
387 }
388
389
390
391 static struct v3_console_ops cons_ops = {
392     .update_screen = screen_update, 
393     .update_cursor = cursor_update,
394     .scroll = scroll,
395 };
396
397
398 static struct v3_device_ops dev_ops = {
399     .free = NULL,
400     .reset = NULL,
401     .start = NULL,
402     .stop = NULL,
403 };
404
405
406
407 static int key_handler(struct vm_device * dev, uint8_t ascii) {
408     struct cons_state * state = (struct cons_state *)dev->private_data;
409
410     PrintDebug("Character recieved: 0x%x\n", ascii);
411
412     // printable
413     if (ascii < 0x80) {
414         const struct key_code * key = &(ascii_to_key_code[ascii]);
415
416         if (deliver_scan_code(dev, (struct key_code *)key) == -1) {
417             PrintError("Could not deliver scan code to vm\n");
418             return -1;
419         }
420
421     } else if (ascii == ESC_CHAR) { // Escape Key
422         // This means that another 2 characters are pending
423         // receive it and deliver accordingly
424         char esc_seq[2] = {0, 0};
425
426         int recv = recv_all(state->client_fd, esc_seq, 2);
427
428         if (recv == -1) {
429             PrintError("Video: Error getting key from network\n");
430             return -1;
431         } else if (recv == 0) {
432             PrintDebug("Video: Client Disconnected\n");
433             return -1;
434         }
435
436
437         if (esc_seq[0] != '[') {
438             PrintDebug("Ignoring non handled escape sequence (codes = %d %d)\n", 
439                        esc_seq[0], esc_seq[1]);
440             return 0;
441         }
442
443
444         if (esc_seq[1] == 'A') {                // UP ARROW
445             struct key_code up = { 0x48, 0 };
446             deliver_scan_code(dev, &up);
447         } else if (esc_seq[1] == 'B') {         // DOWN ARROW
448             struct key_code down = { 0x50, 0 };
449             deliver_scan_code(dev, &down);
450         } else if (esc_seq[1] == 'C') {         // RIGHT ARROW
451             struct key_code right = { 0x4D, 0 };
452             deliver_scan_code(dev, &right);
453         } else if (esc_seq[1] == 'D') {         // LEFT ARROW
454             struct key_code left = { 0x4B, 0 };
455             deliver_scan_code(dev, &left);
456         }
457     } else {
458         PrintError("Invalid character received from network (%c) (code=%d)\n",
459                    ascii, ascii);
460         //      return 0;
461     }
462         
463     return 0;
464 }
465
466 static int cons_server(void * arg) {
467     struct vm_device * dev = (struct vm_device *)arg;
468     struct cons_state * state = (struct cons_state *)dev->private_data;
469     
470     state->server_fd = V3_Create_TCP_Socket();
471
472
473     PrintDebug("Video: Socket File Descriptor: %d\n", state->server_fd);
474
475     if (V3_Bind_Socket(state->server_fd, state->port) == -1) {
476         PrintError("Video: Failed to bind to socket %d\n", state->port);
477     }
478
479     if (V3_Listen_Socket(state->server_fd, 8) == -1) {
480         PrintError("Video: Failed to listen with socket %d\n", state->server_fd);
481     }
482
483     while (1) {
484         uint32_t client_ip;
485         uint32_t client_port;
486         uint8_t ascii_code = 0;
487         int recv = 0;
488
489         if ((state->client_fd = V3_Accept_Socket(state->server_fd, &client_ip,  &client_port)) == -1) {
490             PrintError("Video: Failed to accept connection on port %d\n", client_port);
491         }
492         PrintDebug("Accepted Telnet Console connection\n");
493         state->connected = 1;
494
495         screen_update(0, 0, SCREEN_SIZE, dev);
496
497         while (1) {
498             recv = recv_all(state->client_fd, &ascii_code, sizeof(ascii_code));
499
500             PrintDebug("Telnet console Received %d bytes\n", recv);
501
502             if (recv == -1) {
503                 PrintError("Video: Error getting key from network\n");
504                 break;
505             } else if (recv == 0) {
506                 PrintDebug("Video: Client Disconnected\n");
507                 break;
508             }
509
510             if (key_handler(dev, ascii_code) == -1) {
511                 PrintError("Error in key handler\n");
512                 break;
513             }
514         }
515
516         state->connected = 0;
517         V3_Close_Socket(state->client_fd);
518     }
519 }
520
521
522 static int cons_init(struct guest_info * vm, v3_cfg_tree_t * cfg) {
523     struct cons_state * state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
524     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
525     struct vm_device * frontend = v3_find_dev(vm, v3_cfg_val(frontend_cfg, "id"));
526     char * name = v3_cfg_val(cfg, "name");
527
528
529     state->server_fd = 0;
530     state->client_fd = 0;
531     state->frontend_dev = frontend;
532     state->port = atoi(v3_cfg_val(cfg, "port"));
533     v3_lock_init(&(state->cons_lock));
534
535
536     struct vm_device * dev = v3_allocate_device(name, &dev_ops, state);
537
538     if (v3_attach_device(vm, dev) == -1) {
539         PrintError("Could not attach device %s\n", name);
540         return -1;
541     }
542
543
544     v3_console_register_cga(frontend, &cons_ops, dev);
545
546     V3_CREATE_THREAD(cons_server, dev, "Telnet Console Network Server");
547
548     return 0;
549 }
550
551
552
553 device_register("TELNET_CONSOLE", cons_init)