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.


This patch contains various small fixes. Some are MINIX-specific, some are general.
[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     void * tty;
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_TtyCursorSet(state->tty, x, y) < 0) {
72         PrintError("V3_TtyCursorSet(0x%p, %d, %d) failed\n", state->tty, x, y);
73         return -1;
74     }
75     
76     /* done with console update */
77     if (V3_TtyUpdate(state->tty) < 0) {
78         PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
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_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     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_TtyScroll(state->tty, rows) < 0) {
143             PrintError("V3_TtyScroll(0x%p, %u) failed\n", state->tty, rows);
144             return -1;
145         }
146
147         /* done with console update */
148         if (V3_TtyUpdate(state->tty) < 0) {
149             PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
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     char * ttypath = v3_cfg_val(cfg, "tty");
180
181     /* read configuration */
182     V3_ASSERT(frontend_cfg);
183     V3_ASSERT(frontend_tag);
184     V3_ASSERT(frontend);
185
186
187     /* allocate state */
188     state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
189     V3_ASSERT(state);
190     state->frontend_dev = frontend;
191     V3_ASSERT(ttypath);
192
193     /* open tty for screen display */
194     state->tty = V3_TtyOpen(vm, ttypath, TTY_OPEN_MODE_READ | TTY_OPEN_MODE_WRITE);
195
196     if (!state->tty) {
197         PrintError("Could not open tty %s\n", ttypath);
198         V3_Free(state);
199         return -1;
200     }
201
202     /* allocate device */
203     struct vm_device * dev = v3_allocate_device(dev_id, &dev_ops, state);
204     V3_ASSERT(dev);
205
206     /* attach device to virtual machine */
207     if (v3_attach_device(vm, dev) == -1) {
208         PrintError("Could not attach device %s\n", dev_id);
209         V3_Free(state);
210         return -1;
211     }
212
213     /* attach to front-end display adapter */
214     v3_console_register_cga(frontend, &cons_ops, dev);
215
216     return 0;
217 }
218
219 device_register("CURSES_CONSOLE", cons_init)
220