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.


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