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.


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