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.


Cleanup and sanity-checking of unintentional integer overflow, unsigned/zero comparis...
[palacios.git] / palacios / src / devices / curses_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: Erik van der Kouwe (vdkouwe@cs.vu.nl)
16  *
17  * This is free software.  You are permitted to use,
18  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
19  */
20
21 /* Interface between virtual video card and console */
22
23 #include <palacios/vmm.h>
24 #include <interfaces/vmm_console.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/vm_guest.h>
31
32 #include <devices/console.h>
33
34 #ifndef DEBUG_CURSES_CONS
35 #undef PrintDebug
36 #define PrintDebug(fmt, args...)
37 #endif
38
39 #define BYTES_PER_COL 2
40
41 struct cons_state {
42     v3_console_t cons;
43     int rows;
44     int cols;
45     uint8_t * framebuf;
46     struct vm_device * frontend_dev;
47 };
48
49 static int screen_update(uint_t x, uint_t y, uint_t length, void *private_data);
50
51 static int screen_update_all(void * private_data) {
52     struct vm_device *dev = (struct vm_device *) private_data;
53     struct cons_state *state = (struct cons_state *)dev->private_data;
54     uint_t screen_size;
55
56     screen_size = state->cols * state->rows * BYTES_PER_COL;
57     return screen_update(0, 0, screen_size, private_data);
58 }
59
60 static int cursor_update(uint_t x, uint_t y, void *private_data) 
61 {
62     struct vm_device *dev = (struct vm_device *) private_data;
63     struct cons_state *state = (struct cons_state *) dev->private_data;
64     uint_t offset;
65
66     PrintDebug(VM_NONE, VCORE_NONE, "cursor_update(%d, %d, %p)\n", x, y, private_data);
67
68     /* avoid out-of-range coordinates */
69     if (x >= state->cols) x = state->cols - 1;
70     if (y >= state->rows) y = state->rows - 1;
71     offset = (x + y * state->cols) * BYTES_PER_COL;
72     
73     /* adjust cursor */ 
74     if (v3_console_set_cursor(state->cons, x, y) < 0) {
75         PrintError(VM_NONE, VCORE_NONE, "set cursor (0x%p, %d, %d) failed\n", state->cons, x, y);
76         return -1;
77     }
78     
79     /* done with console update */
80     if (v3_console_update(state->cons) < 0) {
81         PrintError(VM_NONE, VCORE_NONE, "console update (0x%p) failed\n", state->cons);
82         return -1;
83     }
84     
85     return 0;
86 }
87
88 static int screen_update(uint_t x, uint_t y, uint_t length, void * private_data) {
89     struct vm_device * dev = (struct vm_device *)private_data;
90     struct cons_state * state = (struct cons_state *)dev->private_data;
91     uint_t offset = (x + y * state->cols) * BYTES_PER_COL;
92     int i;
93     uint_t cur_x = x;
94     uint_t cur_y = y;
95     
96     if (length > (state->rows * state->cols * BYTES_PER_COL)) {
97         PrintError(VM_NONE, VCORE_NONE, "Screen update larger than curses framebuffer\n");
98         return 0;
99     }
100
101     PrintDebug(VM_NONE, VCORE_NONE, "screen_update(%d, %d, %d, %p)\n", x, y, length, private_data);
102
103     /* grab frame buffer */
104     v3_cons_get_fb(state->frontend_dev, state->framebuf, offset, length);
105     
106     /* update the screen */
107     for (i = 0; i < length; i += 2) {
108         uint_t col_index = i;
109         uint8_t col[2];
110         
111         col[0] = state->framebuf[col_index];     // Character
112         col[1] = state->framebuf[col_index + 1]; // Attribute
113         
114         /* update current character */
115         if (v3_console_set_char(state->cons, cur_x, cur_y, col[0], col[1]) < 0) {
116             PrintError(VM_NONE, VCORE_NONE, "set cursor (0x%p, %d, %d, %d, %d) failed\n", 
117                        state->cons, cur_x, cur_y, col[1], col[0]);
118             return -1;
119         }
120         
121         // CAUTION: the order of these statements is critical
122         // cur_y depends on the previous value of cur_x
123         cur_y = cur_y + ((cur_x + 1) / state->cols);
124         cur_x = (cur_x + 1) % state->cols;
125     }
126     
127     /* done with console update */
128     if (v3_console_update(state->cons) < 0) {
129         PrintError(VM_NONE, VCORE_NONE, "console update(0x%p) failed\n", state->cons);
130         return -1;
131     }
132     
133     return 0;
134 }
135
136 static int scroll(int rows, void * private_data) {
137     struct vm_device *dev = (struct vm_device *)private_data;
138     struct cons_state *state = (struct cons_state *)dev->private_data;
139
140     PrintDebug(VM_NONE, VCORE_NONE, "scroll(%d, %p)\n", rows, private_data);
141
142     if (rows < 0) {
143         /* simply update the screen */
144         return screen_update_all(private_data);
145     }
146
147     if (rows > 0) {
148         /* scroll requested number of lines*/           
149         if (v3_console_scroll(state->cons, rows) < 0) {
150             PrintError(VM_NONE, VCORE_NONE, "console scroll (0x%p, %u) failed\n", state->cons, rows);
151             return -1;
152         }
153
154         /* done with console update */
155         if (v3_console_update(state->cons) < 0) {
156             PrintError(VM_NONE, VCORE_NONE, "console update (0x%p) failed\n", state->cons);
157             return -1;
158         }
159     }
160         
161     return 0;
162 }
163
164 static int set_text_resolution(int cols, int rows, void * private_data) {
165     struct vm_device *dev = (struct vm_device *)private_data;
166     struct cons_state *state = (struct cons_state *)dev->private_data;
167
168     PrintDebug(VM_NONE, VCORE_NONE, "set_text_resolution(%d, %d, %p)\n", cols, rows, private_data);
169
170     /* store resolution for internal use */
171     V3_ASSERT(VM_NONE, VCORE_NONE, cols >= 1);
172     V3_ASSERT(VM_NONE, VCORE_NONE, rows >= 1);
173     state->cols = cols;
174     state->rows = rows;
175
176     /* set notification regarding resolution change */
177     if (v3_console_set_text_resolution(state->cons, cols, rows) < 0) {
178         PrintError(VM_NONE, VCORE_NONE, "console set_text_resolution (0x%p, %u, %u) failed\n", state->cons, cols, rows);
179         return -1;
180     }
181
182     /* update the screen */
183     return screen_update_all(private_data);
184 }
185
186 static int cons_free(struct cons_state * state) {
187     v3_console_close(state->cons);
188
189     // remove host event
190
191     V3_Free(state);
192
193     return 0;
194 }
195
196 static int console_event_handler(struct v3_vm_info * vm, 
197                                  struct v3_console_event * evt, 
198                                  void * priv_data) {
199     return screen_update_all(priv_data);
200 }
201
202 static struct v3_console_ops cons_ops = {
203     .update_screen = screen_update, 
204     .update_cursor = cursor_update,
205     .scroll = scroll,
206     .set_text_resolution = set_text_resolution,
207 };
208
209 static struct v3_device_ops dev_ops = {
210     .free = (int (*)(void *))cons_free,
211 };
212
213 static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) 
214 {
215     struct cons_state * state = NULL;
216     v3_cfg_tree_t * frontend_cfg;
217     const char * frontend_tag;
218     struct vm_device * frontend;
219     char * dev_id = v3_cfg_val(cfg, "ID");
220
221     /* read configuration */
222     frontend_cfg = v3_cfg_subtree(cfg, "frontend");
223     if (!frontend_cfg) {
224         PrintError(vm, VCORE_NONE, "No frontend specification for curses console.\n");
225         return -1;
226     }
227
228     frontend_tag = v3_cfg_val(frontend_cfg, "tag");
229     if (!frontend_tag) {
230         PrintError(vm, VCORE_NONE, "No frontend device tag specified for curses console.\n");
231         return -1;
232     }
233
234     frontend = v3_find_dev(vm, frontend_tag);
235     if (!frontend) {
236         PrintError(vm, VCORE_NONE, "Could not find frontend device %s for curses console.\n",
237                   frontend_tag);
238         return -1;
239     } 
240
241     /* allocate state */
242     state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
243
244     if (!state) {
245         PrintError(vm, VCORE_NONE, "Cannot allocate curses state\n");
246         V3_Free(state);
247         return -1;
248     }
249
250     state->frontend_dev = frontend;
251     state->cols = 80;
252     state->rows = 25;
253     state->framebuf = V3_Malloc(state->cols * state->rows * BYTES_PER_COL);
254
255     if (!state->framebuf) {
256         PrintError(vm, VCORE_NONE, "Cannot allocate frame buffer\n");
257         V3_Free(state);
258         return -1;
259     }
260
261     /* open tty for screen display */
262     state->cons = v3_console_open(vm, state->cols, state->rows);
263
264     if (!state->cons) {
265         PrintError(vm, VCORE_NONE, "Could not open console\n");
266         V3_Free(state->framebuf);
267         V3_Free(state);
268         return -1;
269     }
270
271     /* allocate device */
272     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
273
274     if (dev == NULL) {
275         PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
276         V3_Free(state->framebuf);
277         V3_Free(state);
278         return -1;
279     }
280
281     /* attach to front-end display adapter */
282     v3_console_register_cga(frontend, &cons_ops, dev);
283
284     v3_hook_host_event(vm, HOST_CONSOLE_EVT, V3_HOST_EVENT_HANDLER(console_event_handler), dev);
285
286     return 0;
287 }
288
289 device_register("CURSES_CONSOLE", cons_init)
290