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 private data pointer to per vm state...
[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
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_TtyCursorSet(state->tty, x, y) < 0) {
71         PrintError("V3_TtyCursorSet(0x%p, %d, %d) failed\n", state->tty, x, y);
72         return -1;
73     }
74     
75     /* done with console update */
76     if (V3_TtyUpdate(state->tty) < 0) {
77         PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
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_TtyCharacterSet(state->tty, cur_x, cur_y, col[0], col[1]) < 0) {
107             PrintError("V3_TtyCursorSet(0x%p, %d, %d, %d, %d) failed\n", 
108                        state->tty, 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_TtyUpdate(state->tty) < 0) {
120         PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
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_TtyScroll(state->tty, rows) < 0) {
142             PrintError("V3_TtyScroll(0x%p, %u) failed\n", state->tty, rows);
143             return -1;
144         }
145
146         /* done with console update */
147         if (V3_TtyUpdate(state->tty) < 0) {
148             PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
149             return -1;
150         }
151                 
152         last_offset = BYTES_PER_ROW * (NUM_ROWS - 1);           
153     }
154         
155     return 0;
156 }
157
158 static struct v3_console_ops cons_ops = {
159     .update_screen = screen_update, 
160     .update_cursor = cursor_update,
161     .scroll = scroll,
162 };
163
164 static struct v3_device_ops dev_ops = {
165     .free = NULL,
166     .reset = NULL,
167     .start = NULL,
168     .stop = NULL,
169 };
170
171 static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) 
172 {
173     struct cons_state * state = NULL;
174     v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
175     const char * frontend_tag = v3_cfg_val(frontend_cfg, "tag");
176     struct vm_device * frontend = v3_find_dev(vm, frontend_tag);
177     char * dev_id = v3_cfg_val(cfg, "ID");
178     char * ttypath = v3_cfg_val(cfg, "tty");
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     state->frontend_dev = frontend;
190     V3_ASSERT(ttypath);
191
192     /* open tty for screen display */
193     state->tty = V3_TtyOpen(vm, ttypath, TTY_OPEN_MODE_READ | TTY_OPEN_MODE_WRITE);
194
195     if (!state->tty) {
196         PrintError("Could not open tty %s\n", ttypath);
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