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.


changed device registration interface
[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;
55     uint_t last_x, last_y;
56
57     /* avoid out-of-range coordinates */
58     if (x >= NUM_COLS) x = NUM_COLS - 1;
59     if (y >= NUM_ROWS) y = NUM_ROWS - 1;
60     offset = (x * BYTES_PER_COL) + (y * BYTES_PER_ROW);
61
62     /* unfortunately Palacios sometimes misses some writes, 
63      * but if they are accompanied by a cursor move we may be able to 
64      * detect this
65      */
66     if (offset < last_offset) last_offset = 0;
67
68     if (offset > last_offset) {
69         last_x = (last_offset % BYTES_PER_ROW) / BYTES_PER_COL;
70         last_y = last_offset / BYTES_PER_ROW;
71         screen_update(last_x, last_y, offset - last_offset, private_data);
72     }
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 * BYTES_PER_COL) + (y * BYTES_PER_ROW);
93     uint8_t fb_buf[length];
94     int i;
95     uint_t cur_x = x;
96     uint_t cur_y = y;
97     
98     /* grab frame buffer */
99     memset(fb_buf, 0, length);
100     v3_cons_get_fb(state->frontend_dev, fb_buf, offset, length);
101     
102     /* update the screen */
103     for (i = 0; i < length; i += 2) {
104         uint_t col_index = i;
105         uint8_t col[2];
106         
107         col[0] = fb_buf[col_index];     // Character
108         col[1] = fb_buf[col_index + 1]; // Attribute
109         
110         /* update current character */
111         if (v3_console_set_char(state->cons, cur_x, cur_y, col[0], col[1]) < 0) {
112             PrintError("set cursor (0x%p, %d, %d, %d, %d) failed\n", 
113                        state->cons, cur_x, cur_y, col[1], col[0]);
114             return -1;
115         }
116         
117         // CAUTION: the order of these statements is critical
118         // cur_y depends on the previous value of cur_x
119         cur_y = cur_y + ((cur_x + 1) / NUM_COLS);
120         cur_x = (cur_x + 1) % NUM_COLS;
121     }
122     
123     /* done with console update */
124     if (v3_console_update(state->cons) < 0) {
125         PrintError("console update(0x%p) failed\n", state->cons);
126         return -1;
127     }
128     
129     /* store offset to catch missing notifications */
130     last_offset = offset + length;
131     
132     return 0;
133 }
134
135 static int scroll(int rows, void * private_data) {
136     struct vm_device *dev = (struct vm_device *)private_data;
137     struct cons_state *state = (struct cons_state *)dev->private_data;
138
139     if (rows < 0) {
140         /* simply update the screen */
141         return screen_update(0, 0, SCREEN_SIZE, 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         last_offset = BYTES_PER_ROW * (NUM_ROWS - 1);           
158     }
159         
160     return 0;
161 }
162
163
164 static int cons_free(struct vm_device * dev) {
165     struct cons_state * state = (struct cons_state *)dev->private_data;
166
167     v3_console_close(state->cons);
168
169     // remove host event
170
171     V3_Free(state);
172
173     return 0;
174 }
175
176 static int console_event_handler(struct v3_vm_info * vm, 
177                                  struct v3_console_event * evt, 
178                                  void * priv_data) {
179     screen_update(0, 0, SCREEN_SIZE, priv_data);
180     
181     return 0;
182 }
183
184 static struct v3_console_ops cons_ops = {
185     .update_screen = screen_update, 
186     .update_cursor = cursor_update,
187     .scroll = scroll,
188 };
189
190 static struct v3_device_ops dev_ops = {
191     .free = cons_free,
192 };
193
194 static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) 
195 {
196     struct cons_state * state = NULL;
197     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
198     const char * frontend_tag = v3_cfg_val(frontend_cfg, "tag");
199     struct vm_device * frontend = v3_find_dev(vm, frontend_tag);
200     char * dev_id = v3_cfg_val(cfg, "ID");
201
202     /* read configuration */
203     V3_ASSERT(frontend_cfg);
204     V3_ASSERT(frontend_tag);
205     V3_ASSERT(frontend);
206
207
208     /* allocate state */
209     state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
210     V3_ASSERT(state);
211
212     state->frontend_dev = frontend;
213
214     /* open tty for screen display */
215     state->cons = v3_console_open(vm, NUM_COLS, NUM_ROWS);
216
217     if (!state->cons) {
218         PrintError("Could not open console\n");
219         V3_Free(state);
220         return -1;
221     }
222
223     /* allocate device */
224     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
225  
226     if (dev == NULL) {
227         PrintError("Could not attach device %s\n", dev_id);
228         V3_Free(state);
229         return -1;
230     }
231
232     /* attach to front-end display adapter */
233     v3_console_register_cga(frontend, &cons_ops, dev);
234
235     v3_hook_host_event(vm, HOST_CONSOLE_EVT, V3_HOST_EVENT_HANDLER(console_event_handler), dev);
236
237     return 0;
238 }
239
240 device_register("CURSES_CONSOLE", cons_init)
241