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.


more device free updates
[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 <palacios/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 #define NUM_ROWS 25
35 #define NUM_COLS 80
36 #define BYTES_PER_COL 2
37 #define BYTES_PER_ROW (NUM_COLS * BYTES_PER_COL)
38
39 #define SCREEN_SIZE (BYTES_PER_ROW * NUM_ROWS)
40
41 struct cons_state {
42     v3_console_t cons;
43     struct vm_device * frontend_dev;
44 };
45
46 static int screen_update(uint_t x, uint_t y, uint_t length, void *private_data);
47
48 static uint_t last_offset;
49
50 static int cursor_update(uint_t x, uint_t y, void *private_data) 
51 {
52     struct vm_device *dev = (struct vm_device *) private_data;
53     struct cons_state *state = (struct cons_state *) dev->private_data;
54     uint_t offset = (x * BYTES_PER_COL) + (y * BYTES_PER_ROW);
55     uint_t last_x, last_y;
56
57     /* unfortunately Palacios sometimes misses some writes, 
58      * but if they are accompanied by a cursor move we may be able to 
59      * detect this
60      */
61     if (offset < last_offset) last_offset = 0;
62
63     if (offset > last_offset) {
64         last_x = (last_offset % BYTES_PER_ROW) / BYTES_PER_COL;
65         last_y = last_offset / BYTES_PER_ROW;
66         screen_update(last_x, last_y, offset - last_offset, private_data);
67     }
68     
69     /* adjust cursor */ 
70     if (v3_console_set_cursor(state->cons, x, y) < 0) {
71         PrintError("set cursor (0x%p, %d, %d) failed\n", state->cons, x, y);
72         return -1;
73     }
74     
75     /* done with console update */
76     if (v3_console_update(state->cons) < 0) {
77         PrintError("console update (0x%p) failed\n", state->cons);
78         return -1;
79     }
80     
81     return 0;
82 }
83
84 static int screen_update(uint_t x, uint_t y, uint_t length, void * private_data) {
85     struct vm_device * dev = (struct vm_device *)private_data;
86     struct cons_state * state = (struct cons_state *)dev->private_data;
87     uint_t offset = (x * BYTES_PER_COL) + (y * BYTES_PER_ROW);
88     uint8_t fb_buf[length];
89     int i;
90     uint_t cur_x = x;
91     uint_t cur_y = y;
92     
93     /* grab frame buffer */
94     memset(fb_buf, 0, length);
95     v3_cons_get_fb(state->frontend_dev, fb_buf, offset, length);
96     
97     /* update the screen */
98     for (i = 0; i < length; i += 2) {
99         uint_t col_index = i;
100         uint8_t col[2];
101         
102         col[0] = fb_buf[col_index];     // Character
103         col[1] = fb_buf[col_index + 1]; // Attribute
104         
105         /* update current character */
106         if (v3_console_set_char(state->cons, cur_x, cur_y, col[0], col[1]) < 0) {
107             PrintError("set cursor (0x%p, %d, %d, %d, %d) failed\n", 
108                        state->cons, cur_x, cur_y, col[1], col[0]);
109             return -1;
110         }
111         
112         // CAUTION: the order of these statements is critical
113         // cur_y depends on the previous value of cur_x
114         cur_y = cur_y + ((cur_x + 1) / NUM_COLS);
115         cur_x = (cur_x + 1) % NUM_COLS;
116     }
117     
118     /* done with console update */
119     if (v3_console_update(state->cons) < 0) {
120         PrintError("console update(0x%p) failed\n", state->cons);
121         return -1;
122     }
123     
124     /* store offset to catch missing notifications */
125     last_offset = offset + length;
126     
127     return 0;
128 }
129
130 static int scroll(int rows, void * private_data) {
131     struct vm_device *dev = (struct vm_device *)private_data;
132     struct cons_state *state = (struct cons_state *)dev->private_data;
133
134     if (rows < 0) {
135         /* simply update the screen */
136         return screen_update(0, 0, SCREEN_SIZE, private_data);
137     }
138
139     if (rows > 0) {
140         /* scroll requested number of lines*/           
141         if (v3_console_scroll(state->cons, rows) < 0) {
142             PrintError("console scroll (0x%p, %u) failed\n", state->cons, rows);
143             return -1;
144         }
145
146         /* done with console update */
147         if (v3_console_update(state->cons) < 0) {
148             PrintError("console update (0x%p) failed\n", state->cons);
149             return -1;
150         }
151                 
152         last_offset = BYTES_PER_ROW * (NUM_ROWS - 1);           
153     }
154         
155     return 0;
156 }
157
158
159 static int cons_free(struct vm_device * dev) {
160     struct cons_state * state = (struct cons_state *)dev->private_data;
161
162     v3_console_close(state->cons);
163
164     // remove host event
165
166     V3_Free(state);
167
168     return 0;
169 }
170
171 static int console_event_handler(struct v3_vm_info * vm, 
172                                  struct v3_console_event * evt, 
173                                  void * priv_data) {
174     screen_update(0, 0, SCREEN_SIZE, priv_data);
175     
176     return 0;
177 }
178
179 static struct v3_console_ops cons_ops = {
180     .update_screen = screen_update, 
181     .update_cursor = cursor_update,
182     .scroll = scroll,
183 };
184
185 static struct v3_device_ops dev_ops = {
186     .free = cons_free,
187 };
188
189 static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) 
190 {
191     struct cons_state * state = NULL;
192     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
193     const char * frontend_tag = v3_cfg_val(frontend_cfg, "tag");
194     struct vm_device * frontend = v3_find_dev(vm, frontend_tag);
195     char * dev_id = v3_cfg_val(cfg, "ID");
196
197     /* read configuration */
198     V3_ASSERT(frontend_cfg);
199     V3_ASSERT(frontend_tag);
200     V3_ASSERT(frontend);
201
202
203     /* allocate state */
204     state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
205     V3_ASSERT(state);
206
207     state->frontend_dev = frontend;
208
209     /* open tty for screen display */
210     state->cons = v3_console_open(vm, NUM_COLS, NUM_ROWS);
211
212     if (!state->cons) {
213         PrintError("Could not open console\n");
214         V3_Free(state);
215         return -1;
216     }
217
218     /* allocate device */
219     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, state);
220     V3_ASSERT(dev);
221
222     /* attach device to virtual machine */
223     if (v3_attach_device(vm, dev) == -1) {
224         PrintError("Could not attach device %s\n", dev_id);
225         V3_Free(state);
226         return -1;
227     }
228
229     /* attach to front-end display adapter */
230     v3_console_register_cga(frontend, &cons_ops, dev);
231
232     v3_hook_host_event(vm, HOST_CONSOLE_EVT, V3_HOST_EVENT_HANDLER(console_event_handler), dev);
233
234     return 0;
235 }
236
237 device_register("CURSES_CONSOLE", cons_init)
238