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.


8824447932c4c74c03903c6e4b0709bd75978efb
[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 < 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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "Screen update larger than curses framebuffer\n");
100         return 0;
101     }
102
103     PrintDebug(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "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(VM_NONE, VCORE_NONE, "set_text_resolution(%d, %d, %p)\n", cols, rows, private_data);
171
172     /* store resolution for internal use */
173     V3_ASSERT(VM_NONE, VCORE_NONE, cols >= 1);
174     V3_ASSERT(VM_NONE, VCORE_NONE, 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(VM_NONE, VCORE_NONE, "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;
219     const char * frontend_tag;
220     struct vm_device * frontend;
221     char * dev_id = v3_cfg_val(cfg, "ID");
222
223     /* read configuration */
224     frontend_cfg = v3_cfg_subtree(cfg, "frontend");
225     if (!frontend_cfg) {
226         PrintError(vm, VCORE_NONE, "No frontend specification for curses console.\n");
227         return -1;
228     }
229
230     frontend_tag = v3_cfg_val(frontend_cfg, "tag");
231     if (!frontend_tag) {
232         PrintError(vm, VCORE_NONE, "No frontend device tag specified for curses console.\n");
233         return -1;
234     }
235
236     frontend = v3_find_dev(vm, frontend_tag);
237     if (!frontend) {
238         PrintError(vm, VCORE_NONE, "Could not find frontend device %s for curses console.\n",
239                   frontend_tag);
240         return -1;
241     } 
242
243     /* allocate state */
244     state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
245
246     if (!state) {
247         PrintError(vm, VCORE_NONE, "Cannot allocate curses state\n");
248         V3_Free(state);
249         return -1;
250     }
251
252     state->frontend_dev = frontend;
253     state->cols = 80;
254     state->rows = 25;
255     state->framebuf = V3_Malloc(state->cols * state->rows * BYTES_PER_COL);
256
257     if (!state->framebuf) {
258         PrintError(vm, VCORE_NONE, "Cannot allocate frame buffer\n");
259         V3_Free(state);
260         return -1;
261     }
262
263     /* open tty for screen display */
264     state->cons = v3_console_open(vm, state->cols, state->rows);
265
266     if (!state->cons) {
267         PrintError(vm, VCORE_NONE, "Could not open console\n");
268         V3_Free(state->framebuf);
269         V3_Free(state);
270         return -1;
271     }
272
273     /* allocate device */
274     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
275
276     if (dev == NULL) {
277         PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
278         V3_Free(state->framebuf);
279         V3_Free(state);
280         return -1;
281     }
282
283     /* attach to front-end display adapter */
284     v3_console_register_cga(frontend, &cons_ops, dev);
285
286     v3_hook_host_event(vm, HOST_CONSOLE_EVT, V3_HOST_EVENT_HANDLER(console_event_handler), dev);
287
288     return 0;
289 }
290
291 device_register("CURSES_CONSOLE", cons_init)
292