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.


bug fix to check for illegal memory ranges
[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     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     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("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("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("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("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("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 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("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("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("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("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_Free(state);
401     return 0;
402 }
403
404
405 static struct v3_device_ops dev_ops = {
406     .free = (int (*)(void *))cons_free,
407 };
408
409
410
411 static int key_handler( struct cons_state * state, uint8_t ascii) {
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(state, (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(state, &up);
449         } else if (esc_seq[1] == 'B') {         // DOWN ARROW
450             struct key_code down = { 0x50, 0 };
451             deliver_scan_code(state, &down);
452         } else if (esc_seq[1] == 'C') {         // RIGHT ARROW
453             struct key_code right = { 0x4D, 0 };
454             deliver_scan_code(state, &right);
455         } else if (esc_seq[1] == 'D') {         // LEFT ARROW
456             struct key_code left = { 0x4B, 0 };
457             deliver_scan_code(state, &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 cons_state * state = (struct cons_state *)arg;
470     
471     state->server_fd = V3_Create_TCP_Socket();
472
473
474     PrintDebug("Video: Socket File Descriptor: %d\n", state->server_fd);
475
476     if (V3_Bind_Socket(state->server_fd, state->port) == -1) {
477         PrintError("Video: Failed to bind to socket %d\n", state->port);
478     }
479
480     if (V3_Listen_Socket(state->server_fd, 8) == -1) {
481         PrintError("Video: Failed to listen with socket %d\n", state->server_fd);
482     }
483
484     while (1) {
485         uint32_t client_ip;
486         uint32_t client_port;
487         uint8_t ascii_code = 0;
488         int recv = 0;
489
490         if ((state->client_fd = V3_Accept_Socket(state->server_fd, &client_ip,  &client_port)) == -1) {
491             PrintError("Video: Failed to accept connection on port %d\n", client_port);
492         }
493         PrintDebug("Accepted Telnet Console connection\n");
494         state->connected = 1;
495
496         screen_update(0, 0, SCREEN_SIZE, state);
497
498         while (1) {
499             recv = recv_all(state->client_fd, &ascii_code, sizeof(ascii_code));
500
501             PrintDebug("Telnet console Received %d bytes\n", recv);
502
503             if (recv == -1) {
504                 PrintError("Video: Error getting key from network\n");
505                 break;
506             } else if (recv == 0) {
507                 PrintDebug("Video: Client Disconnected\n");
508                 break;
509             }
510
511             if (key_handler(state, ascii_code) == -1) {
512                 PrintError("Error in key handler\n");
513                 break;
514             }
515         }
516
517         state->connected = 0;
518         V3_Close_Socket(state->client_fd);
519     }
520     
521     return -1;
522 }
523
524
525 static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
526     struct cons_state * state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
527     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
528     struct vm_device * frontend = v3_find_dev(vm, v3_cfg_val(frontend_cfg, "tag"));
529     char * dev_id = v3_cfg_val(cfg, "ID");
530
531     state->vm = vm;
532     state->server_fd = 0;
533     state->client_fd = 0;
534     state->frontend_dev = frontend;
535     state->port = atoi(v3_cfg_val(cfg, "port"));
536     v3_lock_init(&(state->cons_lock));
537
538
539     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
540
541     if (dev == NULL) {
542         PrintError("Could not attach device %s\n", dev_id);
543         V3_Free(state);
544         return -1;
545     }
546
547
548     v3_console_register_cga(frontend, &cons_ops, state);
549
550     V3_CREATE_THREAD(cons_server, state, "Telnet Console Network Server");
551
552     return 0;
553 }
554
555
556
557 device_register("TELNET_CONSOLE", cons_init)