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.


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