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.


change to device configuration syntax
[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 v3_vm_info * vm, v3_cfg_tree_t * cfg) 
174 {
175         struct cons_state * state = NULL;
176         v3_cfg_tree_t * frontend_cfg = v3_cfg_subtree(cfg, "frontend");
177         const char * frontend_tag = v3_cfg_val(frontend_cfg, "tag");
178         struct vm_device * frontend = v3_find_dev(vm, frontend_tag);
179         char * dev_id = v3_cfg_val(cfg, "ID");
180         char * ttypath = v3_cfg_val(cfg, "tty");
181
182         /* read configuration */
183         V3_ASSERT(frontend_cfg);
184         V3_ASSERT(frontend_tag);
185         V3_ASSERT(frontend);
186
187
188         /* allocate state */
189         state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
190         V3_ASSERT(state);
191         state->frontend_dev = frontend;
192         V3_ASSERT(ttypath);
193
194         /* open tty for screen display */
195         state->tty = V3_TtyOpen(ttypath, TTY_OPEN_MODE_READ | TTY_OPEN_MODE_WRITE);
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