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.


deallocation of devices
[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 cons_state * state) {
165     v3_console_close(state->cons);
166
167     // remove host event
168
169     V3_Free(state);
170
171     return 0;
172 }
173
174 static int console_event_handler(struct v3_vm_info * vm, 
175                                  struct v3_console_event * evt, 
176                                  void * priv_data) {
177     screen_update(0, 0, SCREEN_SIZE, priv_data);
178     
179     return 0;
180 }
181
182 static struct v3_console_ops cons_ops = {
183     .update_screen = screen_update, 
184     .update_cursor = cursor_update,
185     .scroll = scroll,
186 };
187
188 static struct v3_device_ops dev_ops = {
189     .free = (int (*)(void *))cons_free,
190 };
191
192 static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) 
193 {
194     struct cons_state * state = NULL;
195     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
196     const char * frontend_tag = v3_cfg_val(frontend_cfg, "tag");
197     struct vm_device * frontend = v3_find_dev(vm, frontend_tag);
198     char * dev_id = v3_cfg_val(cfg, "ID");
199
200     /* read configuration */
201     V3_ASSERT(frontend_cfg);
202     V3_ASSERT(frontend_tag);
203     V3_ASSERT(frontend);
204
205
206     /* allocate state */
207     state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
208     V3_ASSERT(state);
209
210     state->frontend_dev = frontend;
211
212     /* open tty for screen display */
213     state->cons = v3_console_open(vm, NUM_COLS, NUM_ROWS);
214
215     if (!state->cons) {
216         PrintError("Could not open console\n");
217         V3_Free(state);
218         return -1;
219     }
220
221     /* allocate device */
222     struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
223  
224     if (dev == NULL) {
225         PrintError("Could not attach device %s\n", dev_id);
226         V3_Free(state);
227         return -1;
228     }
229
230     /* attach to front-end display adapter */
231     v3_console_register_cga(frontend, &cons_ops, dev);
232
233     v3_hook_host_event(vm, HOST_CONSOLE_EVT, V3_HOST_EVENT_HANDLER(console_event_handler), dev);
234
235     return 0;
236 }
237
238 device_register("CURSES_CONSOLE", cons_init)
239