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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
15 * Author: Erik van der Kouwe (vdkouwe@cs.vu.nl)
17 * This is free software. You are permitted to use,
18 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21 /* Interface between virtual video card and console */
23 #include <palacios/vmm.h>
24 #include <interfaces/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>
32 #include <devices/console.h>
34 #ifndef DEBUG_CURSES_CONS
36 #define PrintDebug(fmt, args...)
39 #define BYTES_PER_COL 2
46 struct vm_device * frontend_dev;
49 static int screen_update(uint_t x, uint_t y, uint_t length, void *private_data);
51 static int screen_update_all(void * private_data) {
52 struct vm_device *dev = (struct vm_device *) private_data;
53 struct cons_state *state = (struct cons_state *)dev->private_data;
56 screen_size = state->cols * state->rows * BYTES_PER_COL;
57 return screen_update(0, 0, screen_size, private_data);
60 static int cursor_update(uint_t x, uint_t y, void *private_data)
62 struct vm_device *dev = (struct vm_device *) private_data;
63 struct cons_state *state = (struct cons_state *) dev->private_data;
66 PrintDebug(VM_NONE, VCORE_NONE, "cursor_update(%d, %d, %p)\n", x, y, private_data);
68 /* avoid out-of-range coordinates */
69 if (x >= state->cols) x = state->cols - 1;
70 if (y >= state->rows) y = state->rows - 1;
71 offset = (x + y * state->cols) * BYTES_PER_COL;
74 if (v3_console_set_cursor(state->cons, x, y) < 0) {
75 PrintError(VM_NONE, VCORE_NONE, "set cursor (0x%p, %d, %d) failed\n", state->cons, x, y);
79 /* done with console update */
80 if (v3_console_update(state->cons) < 0) {
81 PrintError(VM_NONE, VCORE_NONE, "console update (0x%p) failed\n", state->cons);
88 static int screen_update(uint_t x, uint_t y, uint_t length, void * private_data) {
89 struct vm_device * dev = (struct vm_device *)private_data;
90 struct cons_state * state = (struct cons_state *)dev->private_data;
91 uint_t offset = (x + y * state->cols) * BYTES_PER_COL;
96 if (length > (state->rows * state->cols * BYTES_PER_COL)) {
97 PrintError(VM_NONE, VCORE_NONE, "Screen update larger than curses framebuffer\n");
101 PrintDebug(VM_NONE, VCORE_NONE, "screen_update(%d, %d, %d, %p)\n", x, y, length, private_data);
103 /* grab frame buffer */
104 v3_cons_get_fb(state->frontend_dev, state->framebuf, offset, length);
106 /* update the screen */
107 for (i = 0; i < length; i += 2) {
108 uint_t col_index = i;
111 col[0] = state->framebuf[col_index]; // Character
112 col[1] = state->framebuf[col_index + 1]; // Attribute
114 /* update current character */
115 if (v3_console_set_char(state->cons, cur_x, cur_y, col[0], col[1]) < 0) {
116 PrintError(VM_NONE, VCORE_NONE, "set cursor (0x%p, %d, %d, %d, %d) failed\n",
117 state->cons, cur_x, cur_y, col[1], col[0]);
121 // CAUTION: the order of these statements is critical
122 // cur_y depends on the previous value of cur_x
123 cur_y = cur_y + ((cur_x + 1) / state->cols);
124 cur_x = (cur_x + 1) % state->cols;
127 /* done with console update */
128 if (v3_console_update(state->cons) < 0) {
129 PrintError(VM_NONE, VCORE_NONE, "console update(0x%p) failed\n", state->cons);
136 static int scroll(int rows, void * private_data) {
137 struct vm_device *dev = (struct vm_device *)private_data;
138 struct cons_state *state = (struct cons_state *)dev->private_data;
140 PrintDebug(VM_NONE, VCORE_NONE, "scroll(%d, %p)\n", rows, private_data);
143 /* simply update the screen */
144 return screen_update_all(private_data);
148 /* scroll requested number of lines*/
149 if (v3_console_scroll(state->cons, rows) < 0) {
150 PrintError(VM_NONE, VCORE_NONE, "console scroll (0x%p, %u) failed\n", state->cons, rows);
154 /* done with console update */
155 if (v3_console_update(state->cons) < 0) {
156 PrintError(VM_NONE, VCORE_NONE, "console update (0x%p) failed\n", state->cons);
164 static int set_text_resolution(int cols, int rows, void * private_data) {
165 struct vm_device *dev = (struct vm_device *)private_data;
166 struct cons_state *state = (struct cons_state *)dev->private_data;
168 PrintDebug(VM_NONE, VCORE_NONE, "set_text_resolution(%d, %d, %p)\n", cols, rows, private_data);
170 /* store resolution for internal use */
171 V3_ASSERT(VM_NONE, VCORE_NONE, cols >= 1);
172 V3_ASSERT(VM_NONE, VCORE_NONE, rows >= 1);
176 /* set notification regarding resolution change */
177 if (v3_console_set_text_resolution(state->cons, cols, rows) < 0) {
178 PrintError(VM_NONE, VCORE_NONE, "console set_text_resolution (0x%p, %u, %u) failed\n", state->cons, cols, rows);
182 /* update the screen */
183 return screen_update_all(private_data);
186 static int cons_free(struct cons_state * state) {
187 v3_console_close(state->cons);
196 static int console_event_handler(struct v3_vm_info * vm,
197 struct v3_console_event * evt,
199 return screen_update_all(priv_data);
202 static struct v3_console_ops cons_ops = {
203 .update_screen = screen_update,
204 .update_cursor = cursor_update,
206 .set_text_resolution = set_text_resolution,
209 static struct v3_device_ops dev_ops = {
210 .free = (int (*)(void *))cons_free,
213 static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg)
215 struct cons_state * state = NULL;
216 v3_cfg_tree_t * frontend_cfg;
217 const char * frontend_tag;
218 struct vm_device * frontend;
219 char * dev_id = v3_cfg_val(cfg, "ID");
221 /* read configuration */
222 frontend_cfg = v3_cfg_subtree(cfg, "frontend");
224 PrintError(vm, VCORE_NONE, "No frontend specification for curses console.\n");
228 frontend_tag = v3_cfg_val(frontend_cfg, "tag");
230 PrintError(vm, VCORE_NONE, "No frontend device tag specified for curses console.\n");
234 frontend = v3_find_dev(vm, frontend_tag);
236 PrintError(vm, VCORE_NONE, "Could not find frontend device %s for curses console.\n",
242 state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
245 PrintError(vm, VCORE_NONE, "Cannot allocate curses state\n");
250 state->frontend_dev = frontend;
253 state->framebuf = V3_Malloc(state->cols * state->rows * BYTES_PER_COL);
255 if (!state->framebuf) {
256 PrintError(vm, VCORE_NONE, "Cannot allocate frame buffer\n");
261 /* open tty for screen display */
262 state->cons = v3_console_open(vm, state->cols, state->rows);
265 PrintError(vm, VCORE_NONE, "Could not open console\n");
266 V3_Free(state->framebuf);
271 /* allocate device */
272 struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, state);
275 PrintError(vm, VCORE_NONE, "Could not attach device %s\n", dev_id);
276 V3_Free(state->framebuf);
281 /* attach to front-end display adapter */
282 v3_console_register_cga(frontend, &cons_ops, dev);
284 v3_hook_host_event(vm, HOST_CONSOLE_EVT, V3_HOST_EVENT_HANDLER(console_event_handler), dev);
289 device_register("CURSES_CONSOLE", cons_init)