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.


add console hook support
[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
31 #include <devices/console.h>
32
33 #define NUM_ROWS 25
34 #define NUM_COLS 80
35 #define BYTES_PER_COL 2
36 #define BYTES_PER_ROW (NUM_COLS * BYTES_PER_COL)
37
38 #define SCREEN_SIZE (BYTES_PER_ROW * NUM_ROWS)
39
40 struct cons_state 
41 {
42         void *tty;
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         if (offset > last_offset) {
63                 last_x = (last_offset % BYTES_PER_ROW) / BYTES_PER_COL;
64                 last_y = last_offset / BYTES_PER_ROW;
65                 screen_update(last_x, last_y, offset - last_offset, private_data);
66         }
67
68         /* adjust cursor */     
69         if (V3_TtyCursorSet(state->tty, x, y) < 0) {
70                 PrintError("V3_TtyCursorSet(0x%p, %d, %d) failed\n", state->tty, x, y);
71                 return -1;
72         }
73
74         /* done with console update */
75         if (V3_TtyUpdate(state->tty) < 0) {
76                 PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
77                 return -1;
78         }
79
80         return 0;
81 }
82
83 static int screen_update(uint_t x, uint_t y, uint_t length, void *private_data) 
84 {
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         {
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_TtyCharacterSet(state->tty, cur_x, cur_y, col[0], col[1]) < 0) {
108                         PrintError("V3_TtyCursorSet(0x%p, %d, %d, %d, %d) failed\n", 
109                                 state->tty, 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_TtyUpdate(state->tty) < 0) {
121                 PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
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 {
133         struct vm_device *dev = (struct vm_device *)private_data;
134         struct cons_state *state = (struct cons_state *)dev->private_data;
135
136         if (rows < 0) {
137                 /* simply update the screen */
138                 return screen_update(0, 0, SCREEN_SIZE, private_data);
139         }
140
141         if (rows > 0) {
142                 /* scroll requested number of lines*/           
143                 if (V3_TtyScroll(state->tty, rows) < 0) {
144                         PrintError("V3_TtyScroll(0x%p, %u) failed\n", state->tty, rows);
145                         return -1;
146                 }
147
148                 /* done with console update */
149                 if (V3_TtyUpdate(state->tty) < 0) {
150                         PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
151                         return -1;
152                 }
153                 
154                 last_offset = BYTES_PER_ROW * (NUM_ROWS - 1);           
155         }
156         
157         return 0;
158 }
159
160 static struct v3_console_ops cons_ops = {
161     .update_screen = screen_update, 
162     .update_cursor = cursor_update,
163     .scroll = scroll,
164 };
165
166 static struct v3_device_ops dev_ops = {
167     .free = NULL,
168     .reset = NULL,
169     .start = NULL,
170     .stop = NULL,
171 };
172
173 static int cons_init(struct guest_info * vm, v3_cfg_tree_t * cfg) 
174 {
175         struct cons_state * state;
176         v3_cfg_tree_t * frontend_cfg;
177         const char *frontend_tag;
178         struct vm_device * frontend;
179         char *name, *ttypath;
180
181         /* read configuration */
182         frontend_cfg = v3_cfg_subtree(cfg, "frontend");
183         V3_ASSERT(frontend_cfg);
184         frontend_tag = v3_cfg_val(frontend_cfg, "tag");
185         V3_ASSERT(frontend_tag);
186         frontend = v3_find_dev(vm, frontend_tag);
187         V3_ASSERT(frontend);
188         name = v3_cfg_val(cfg, "name");
189
190         /* allocate state */
191         state = (struct cons_state *) V3_Malloc(sizeof(struct cons_state));
192         V3_ASSERT(state);
193         state->frontend_dev = frontend;
194         ttypath = v3_cfg_val(cfg, "tty");
195         V3_ASSERT(ttypath);
196
197         /* open tty for screen display */
198         state->tty = V3_TtyOpen(ttypath, TTY_OPEN_MODE_READ | TTY_OPEN_MODE_WRITE);
199         if (!state->tty) {
200                 PrintError("Could not open tty %s\n", ttypath);
201                 V3_Free(state);
202                 return -1;
203         }
204
205         /* allocate device */
206         struct vm_device *dev = v3_allocate_device(name, &dev_ops, state);
207         V3_ASSERT(dev);
208
209         /* attach device to virtual machine */
210         if (v3_attach_device(vm, dev) == -1) {
211                 PrintError("Could not attach device %s\n", name);
212                 V3_Free(state);
213                 return -1;
214         }
215
216         /* attach to front-end display adapter */
217         v3_console_register_cga(frontend, &cons_ops, dev);
218
219         return 0;
220 }
221
222 device_register("CURSES_CONSOLE", cons_init)
223