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.


be40ba40ad8b74d2b631e62e8219f002c52873ac
[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 <interfaces/vmm_socket.h>
31
32 #include <devices/console.h>
33
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     v3_sock_t server_fd;
52     v3_sock_t client_fd;
53
54     uint16_t port;
55
56     int connected;
57
58     v3_lock_t cons_lock;
59
60     struct v3_vm_info * vm;
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 cons_state * state, 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(VM_NONE, VCORE_NONE, "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(state->vm, &key_shift) == -1) {
124             PrintError(VM_NONE, VCORE_NONE, "Video: Error delivering key event\n");
125             return -1;
126         }
127     }
128
129     // Press
130     if (v3_deliver_keyboard_event(state->vm, &key_event) == -1) {
131         PrintError(VM_NONE, VCORE_NONE, "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(state->vm, &key_event) == -1) {
139         PrintError(VM_NONE, VCORE_NONE, "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(state->vm, &key_shift) == -1) {
148             PrintError(VM_NONE, VCORE_NONE, "Video: Error delivering key event\n");
149             return -1;
150         }
151     }
152
153     PrintDebug(VM_NONE, VCORE_NONE, "Finished with Key delivery\n");
154     return 0;
155 }
156
157
158
159
160 static int recv_all(v3_sock_t socket, char * buf, int length) {
161     int bytes_read = 0;
162     
163     PrintDebug(VM_NONE, VCORE_NONE, "Reading %d bytes\n", length - bytes_read);
164     while (bytes_read < length) {
165         int tmp_bytes = v3_socket_recv(socket, buf + bytes_read, length - bytes_read);
166         PrintDebug(VM_NONE, VCORE_NONE, "Received %d bytes\n", tmp_bytes);
167
168         if (tmp_bytes == 0) {
169             PrintError(VM_NONE, VCORE_NONE, "Connection Closed unexpectedly\n");
170             return 0;
171         } else if (tmp_bytes == -1) {
172             PrintError(VM_NONE, VCORE_NONE, "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 v3_sock_t 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_socket_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 cons_state * state, uint8_t  x, uint8_t  y, uint8_t attrib, uint8_t val) {
218     uint8_t fg_color = fg_color_map[(attrib & 0x0f) % 16];
219     uint8_t bg_color = bg_color_map[(attrib & 0xf0) % 16];
220     uint8_t buf[32];
221     int ret = 0;
222     int i = 0;
223
224     memset(buf, 0, 32);
225
226     buf[i++] = ESC_CHAR;
227     buf[i++] = '[';
228
229     INT_TO_CHAR(i, buf, y + 1);
230
231     buf[i++] = ';';
232
233     INT_TO_CHAR(i, buf, x + 1);
234
235     buf[i++] = 'H';
236     buf[i++] = ESC_CHAR;
237     buf[i++] = '[';
238     buf[i++] = '0';
239     buf[i++] = 'm';
240     buf[i++] = ESC_CHAR;
241     buf[i++] = '[';
242
243     INT_TO_CHAR(i, buf, fg_color);
244
245     buf[i++] = ';';
246
247     INT_TO_CHAR(i, buf, bg_color);
248
249     buf[i++] = 'm';
250
251     // Add value
252
253     buf[i++] = ESC_CHAR;
254     buf[i++] = '[';
255     INT_TO_CHAR(i, buf, y + 1);
256     buf[i++] = ';';
257     INT_TO_CHAR(i, buf, x + 1);
258     buf[i++] = 'H';
259     buf[i++] = val;
260
261     PrintDebug(VM_NONE, VCORE_NONE, "printing value '%c'\n", val);
262
263     if (state->connected) {
264         uint64_t start, end;
265
266         rdtscll(start);
267         ret =  send_all(state->client_fd, buf, 32);
268         rdtscll(end);
269
270         PrintDebug(VM_NONE, VCORE_NONE, "Sendall latency=%d cycles\n", (uint32_t)(end - start));
271     }
272
273     return ret;
274 }
275
276
277
278 static int cursor_update(uint_t x, uint_t y, void * private_data) {
279     struct cons_state * state = (struct cons_state *)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 cons_state * state = (struct cons_state *)private_data;
309     uint_t offset = (x * BYTES_PER_COL) + (y * BYTES_PER_ROW);
310     uint8_t fb_buf[length];
311     int i = 0;
312     uint_t cur_x = x;
313     uint_t cur_y = y;
314     addr_t irq_state = 0;
315     int ret = 0;
316
317     memset(fb_buf, 0, length);
318     
319
320
321     irq_state = v3_lock_irqsave(state->cons_lock);
322
323     v3_cons_get_fb(state->frontend_dev, fb_buf, offset, length);
324
325     v3_unlock_irqrestore(state->cons_lock, irq_state);
326
327
328     for (i = 0; i < length; i += 2) {
329         uint_t col_index = i;
330         uint8_t col[2];
331
332         col[0] = fb_buf[col_index];     // Character
333         col[1] = fb_buf[col_index + 1]; // Attribute
334
335         irq_state = v3_lock_irqsave(state->cons_lock);
336
337         if (send_update(state, cur_x, cur_y, col[1], col[0]) == -1) {
338             PrintError(VM_NONE, VCORE_NONE, "Could not send attribute to telnet session\n");
339             ret = -1;
340             break;
341         }
342
343         v3_unlock_irqrestore(state->cons_lock, irq_state);
344                                     
345
346         // CAUTION: the order of these statements is critical
347         // cur_y depends on the previous value of cur_x
348         cur_y = cur_y + ((cur_x + 1) / NUM_COLS);
349         cur_x = (cur_x + 1) % NUM_COLS;
350     }
351
352
353     return ret;
354 }
355
356 static int scroll(int rows, void * private_data) {
357     struct cons_state * state = (struct cons_state *)private_data;
358     addr_t irq_state = 0;
359     int ret = 0;
360
361     if (rows > 0) {
362         int i = 0;
363
364         irq_state = v3_lock_irqsave(state->cons_lock);
365
366         for (i = rows; i > 0; i--) {
367             uint8_t message[2] = { ESC_CHAR, 'D' };
368
369             if (state->connected) {
370                 if (send_all(state->client_fd, message, sizeof(message)) == -1) {
371                     PrintError(VM_NONE, VCORE_NONE, "Could not send scroll command\n");
372                     ret = -1;
373                     break;
374                 }
375             }
376         }
377         
378         v3_unlock_irqrestore(state->cons_lock, irq_state);
379
380     } else if (rows < 0) {
381         ret = screen_update(0, 0, SCREEN_SIZE, private_data);
382     }
383
384     return ret;
385 }
386
387
388
389 static struct v3_console_ops cons_ops = {
390     .update_screen = screen_update, 
391     .update_cursor = cursor_update,
392     .scroll = scroll,
393     .set_text_resolution = NULL,
394 };
395
396 static int cons_free(struct cons_state * state) {
397
398     // kill thread... ?
399
400     v3_lock_deinit(&(state->cons_lock));
401
402     V3_Free(state);
403     return 0;
404 }
405
406
407 static struct v3_device_ops dev_ops = {
408     .free = (int (*)(void *))cons_free,
409 };
410
411
412
413 static int key_handler( struct cons_state * state, uint8_t ascii) {
414     PrintDebug(VM_NONE, VCORE_NONE, "Character recieved: 0x%x\n", ascii);
415
416     // printable
417     if (ascii < 0x80) {
418         const struct key_code * key = &(ascii_to_key_code[ascii]);
419
420         if (deliver_scan_code(state, (struct key_code *)key) == -1) {
421             PrintError(VM_NONE, VCORE_NONE, "Could not deliver scan code to vm\n");
422             return -1;
423         }
424
425     } else if (ascii == ESC_CHAR) { // Escape Key
426         // This means that another 2 characters are pending
427         // receive it and deliver accordingly
428         char esc_seq[2] = {0, 0};
429
430         int recv = recv_all(state->client_fd, esc_seq, 2);
431
432         if (recv == -1) {
433             PrintError(VM_NONE, VCORE_NONE, "Video: Error getting key from network\n");
434             return -1;
435         } else if (recv == 0) {
436             PrintDebug(VM_NONE, VCORE_NONE, "Video: Client Disconnected\n");
437             return -1;
438         }
439
440
441         if (esc_seq[0] != '[') {
442             PrintDebug(VM_NONE, VCORE_NONE, "Ignoring non handled escape sequence (codes = %d %d)\n", 
443                        esc_seq[0], esc_seq[1]);
444             return 0;
445         }
446
447
448         if (esc_seq[1] == 'A') {                // UP ARROW
449             struct key_code up = { 0x48, 0 };
450             deliver_scan_code(state, &up);
451         } else if (esc_seq[1] == 'B') {         // DOWN ARROW
452             struct key_code down = { 0x50, 0 };
453             deliver_scan_code(state, &down);
454         } else if (esc_seq[1] == 'C') {         // RIGHT ARROW
455             struct key_code right = { 0x4D, 0 };
456             deliver_scan_code(state, &right);
457         } else if (esc_seq[1] == 'D') {         // LEFT ARROW
458             struct key_code left = { 0x4B, 0 };
459             deliver_scan_code(state, &left);
460         }
461     } else {
462         PrintError(VM_NONE, VCORE_NONE, "Invalid character received from network (%c) (code=%d)\n",
463                    ascii, ascii);
464         //      return 0;
465     }
466         
467     return 0;
468 }
469
470 static int cons_server(void * arg) {
471     struct cons_state * state = (struct cons_state *)arg;
472     
473     state->server_fd = v3_create_tcp_socket(state->vm);
474
475
476     PrintDebug(VM_NONE, VCORE_NONE, "Video: Socket File Descriptor: 0x%p\n", state->server_fd);
477
478     if (v3_socket_bind(state->server_fd, state->port) == -1) {
479         PrintError(VM_NONE, VCORE_NONE, "Video: Failed to bind to socket %d\n", state->port);
480     }
481
482     if (v3_socket_listen(state->server_fd, 8) == -1) {
483         PrintError(VM_NONE, VCORE_NONE, "Video: Failed to listen with socket 0x%p\n", state->server_fd);
484     }
485
486     while (1) {
487         uint32_t client_ip;
488         uint32_t client_port;
489         uint8_t ascii_code = 0;
490         int recv = 0;
491
492         if ((state->client_fd = v3_socket_accept(state->server_fd, &client_ip,  &client_port)) == 0) {
493             PrintError(VM_NONE, VCORE_NONE, "Video: Failed to accept connection on port %d\n", client_port);
494         }
495         PrintDebug(VM_NONE, VCORE_NONE, "Accepted Telnet Console connection\n");
496         state->connected = 1;
497
498         screen_update(0, 0, SCREEN_SIZE, state);
499
500         while (1) {
501             recv = recv_all(state->client_fd, &ascii_code, sizeof(ascii_code));
502
503             PrintDebug(VM_NONE, VCORE_NONE, "Telnet console Received %d bytes\n", recv);
504
505             if (recv == -1) {
506                 PrintError(VM_NONE, VCORE_NONE, "Video: Error getting key from network\n");
507                 break;
508             } else if (recv == 0) {
509                 PrintDebug(VM_NONE, VCORE_NONE, "Video: Client Disconnected\n");
510                 break;
511             }
512
513             if (key_handler(state, ascii_code) == -1) {
514                 PrintError(VM_NONE, VCORE_NONE, "Error in key handler\n");
515                 break;
516             }
517         }
518
519         state->connected = 0;
520         v3_socket_close(state->client_fd);
521     }
522     
523     return -1;
524 }
525
526
527 static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
528     struct cons_state * state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
529     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
530     struct vm_device * frontend = v3_find_dev(vm, v3_cfg_val(frontend_cfg, "tag"));
531     char * dev_id = v3_cfg_val(cfg, "ID");
532
533     if (!state) {
534         PrintError(vm, VCORE_NONE, "Cannot allocate in init\n");
535         return -1;
536     }
537
538
539     state->vm = vm;
540     state->server_fd = 0;
541     state->client_fd = 0;
542     state->frontend_dev = frontend;
543     state->port = atoi(v3_cfg_val(cfg, "port"));
544     v3_lock_init(&(state->cons_lock));
545
546
547     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
548
549     if (dev == NULL) {
550         PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
551         V3_Free(state);
552         return -1;
553     }
554
555
556     v3_console_register_cga(frontend, &cons_ops, state);
557
558     V3_CREATE_AND_START_THREAD(cons_server, state, "Telnet Console Network Server", 0);
559
560     return 0;
561 }
562
563
564
565 device_register("TELNET_CONSOLE", cons_init)