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.


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