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.


fixed stack overflow bug in curses console framebuffer
[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("cursor_update(%d, %d, %p)\n", x, y, private_data);
67
68     /* avoid out-of-range coordinates */
69     if (x < 0) x = 0;
70     if (y < 0) y = 0;
71     if (x >= state->cols) x = state->cols - 1;
72     if (y >= state->rows) y = state->rows - 1;
73     offset = (x + y * state->cols) * BYTES_PER_COL;
74     
75     /* adjust cursor */ 
76     if (v3_console_set_cursor(state->cons, x, y) < 0) {
77         PrintError("set cursor (0x%p, %d, %d) failed\n", state->cons, x, y);
78         return -1;
79     }
80     
81     /* done with console update */
82     if (v3_console_update(state->cons) < 0) {
83         PrintError("console update (0x%p) failed\n", state->cons);
84         return -1;
85     }
86     
87     return 0;
88 }
89
90 static int screen_update(uint_t x, uint_t y, uint_t length, void * private_data) {
91     struct vm_device * dev = (struct vm_device *)private_data;
92     struct cons_state * state = (struct cons_state *)dev->private_data;
93     uint_t offset = (x + y * state->cols) * BYTES_PER_COL;
94     int i;
95     uint_t cur_x = x;
96     uint_t cur_y = y;
97     
98     if (length > (state->rows * state->cols * BYTES_PER_COL)) {
99         PrintError("Screen update larger than curses framebuffer\n");
100         return 0;
101     }
102
103     PrintDebug("screen_update(%d, %d, %d, %p)\n", x, y, length, private_data);
104
105     /* grab frame buffer */
106     v3_cons_get_fb(state->frontend_dev, state->framebuf, offset, length);
107     
108     /* update the screen */
109     for (i = 0; i < length; i += 2) {
110         uint_t col_index = i;
111         uint8_t col[2];
112         
113         col[0] = state->framebuf[col_index];     // Character
114         col[1] = state->framebuf[col_index + 1]; // Attribute
115         
116         /* update current character */
117         if (v3_console_set_char(state->cons, cur_x, cur_y, col[0], col[1]) < 0) {
118             PrintError("set cursor (0x%p, %d, %d, %d, %d) failed\n", 
119                        state->cons, cur_x, cur_y, col[1], col[0]);
120             return -1;
121         }
122         
123         // CAUTION: the order of these statements is critical
124         // cur_y depends on the previous value of cur_x
125         cur_y = cur_y + ((cur_x + 1) / state->cols);
126         cur_x = (cur_x + 1) % state->cols;
127     }
128     
129     /* done with console update */
130     if (v3_console_update(state->cons) < 0) {
131         PrintError("console update(0x%p) failed\n", state->cons);
132         return -1;
133     }
134     
135     return 0;
136 }
137
138 static int scroll(int rows, void * private_data) {
139     struct vm_device *dev = (struct vm_device *)private_data;
140     struct cons_state *state = (struct cons_state *)dev->private_data;
141
142     PrintDebug("scroll(%d, %p)\n", rows, private_data);
143
144     if (rows < 0) {
145         /* simply update the screen */
146         return screen_update_all(private_data);
147     }
148
149     if (rows > 0) {
150         /* scroll requested number of lines*/           
151         if (v3_console_scroll(state->cons, rows) < 0) {
152             PrintError("console scroll (0x%p, %u) failed\n", state->cons, rows);
153             return -1;
154         }
155
156         /* done with console update */
157         if (v3_console_update(state->cons) < 0) {
158             PrintError("console update (0x%p) failed\n", state->cons);
159             return -1;
160         }
161     }
162         
163     return 0;
164 }
165
166 static int set_text_resolution(int cols, int rows, void * private_data) {
167     struct vm_device *dev = (struct vm_device *)private_data;
168     struct cons_state *state = (struct cons_state *)dev->private_data;
169
170     PrintDebug("set_text_resolution(%d, %d, %p)\n", cols, rows, private_data);
171
172     /* store resolution for internal use */
173     V3_ASSERT(cols >= 1);
174     V3_ASSERT(rows >= 1);
175     state->cols = cols;
176     state->rows = rows;
177
178     /* set notification regarding resolution change */
179     if (v3_console_set_text_resolution(state->cons, cols, rows) < 0) {
180         PrintError("console set_text_resolution (0x%p, %u, %u) failed\n", state->cons, cols, rows);
181         return -1;
182     }
183
184     /* update the screen */
185     return screen_update_all(private_data);
186 }
187
188 static int cons_free(struct cons_state * state) {
189     v3_console_close(state->cons);
190
191     // remove host event
192
193     V3_Free(state);
194
195     return 0;
196 }
197
198 static int console_event_handler(struct v3_vm_info * vm, 
199                                  struct v3_console_event * evt, 
200                                  void * priv_data) {
201     return screen_update_all(priv_data);
202 }
203
204 static struct v3_console_ops cons_ops = {
205     .update_screen = screen_update, 
206     .update_cursor = cursor_update,
207     .scroll = scroll,
208     .set_text_resolution = set_text_resolution,
209 };
210
211 static struct v3_device_ops dev_ops = {
212     .free = (int (*)(void *))cons_free,
213 };
214
215 static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) 
216 {
217     struct cons_state * state = NULL;
218     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
219     const char * frontend_tag = v3_cfg_val(frontend_cfg, "tag");
220     struct vm_device * frontend = v3_find_dev(vm, frontend_tag);
221     char * dev_id = v3_cfg_val(cfg, "ID");
222
223     /* read configuration */
224     V3_ASSERT(frontend_cfg);
225     V3_ASSERT(frontend_tag);
226     V3_ASSERT(frontend);
227
228
229     /* allocate state */
230     state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
231     V3_ASSERT(state);
232
233     state->frontend_dev = frontend;
234     state->cols = 80;
235     state->rows = 25;
236     state->framebuf = V3_Malloc(state->cols * state->rows * BYTES_PER_COL);
237
238
239     /* open tty for screen display */
240     state->cons = v3_console_open(vm, state->cols, state->rows);
241
242     if (!state->cons) {
243         PrintError("Could not open console\n");
244         V3_Free(state);
245         return -1;
246     }
247
248     /* allocate device */
249     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
250
251     if (dev == NULL) {
252         PrintError("Could not attach device %s\n", dev_id);
253         V3_Free(state);
254         return -1;
255     }
256
257     /* attach to front-end display adapter */
258     v3_console_register_cga(frontend, &cons_ops, dev);
259
260     v3_hook_host_event(vm, HOST_CONSOLE_EVT, V3_HOST_EVENT_HANDLER(console_event_handler), dev);
261
262     return 0;
263 }
264
265 device_register("CURSES_CONSOLE", cons_init)
266