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 <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>
31 #include <devices/console.h>
35 #define BYTES_PER_COL 2
36 #define BYTES_PER_ROW (NUM_COLS * BYTES_PER_COL)
38 #define SCREEN_SIZE (BYTES_PER_ROW * NUM_ROWS)
43 struct vm_device *frontend_dev;
46 static int screen_update(uint_t x, uint_t y, uint_t length, void *private_data);
48 static uint_t last_offset;
50 static int cursor_update(uint_t x, uint_t y, void *private_data)
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;
57 /* unfortunately Palacios sometimes misses some writes,
58 * but if they are accompanied by a cursor move we may be able to
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);
69 if (V3_TtyCursorSet(state->tty, x, y) < 0) {
70 PrintError("V3_TtyCursorSet(0x%p, %d, %d) failed\n", state->tty, x, y);
74 /* done with console update */
75 if (V3_TtyUpdate(state->tty) < 0) {
76 PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
83 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];
93 /* grab frame buffer */
94 memset(fb_buf, 0, length);
95 v3_cons_get_fb(state->frontend_dev, fb_buf, offset, length);
97 /* update the screen */
98 for (i = 0; i < length; i += 2)
100 uint_t col_index = i;
103 col[0] = fb_buf[col_index]; // Character
104 col[1] = fb_buf[col_index + 1]; // Attribute
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]);
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;
119 /* done with console update */
120 if (V3_TtyUpdate(state->tty) < 0) {
121 PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
125 /* store offset to catch missing notifications */
126 last_offset = offset + length;
131 static int scroll(int rows, void *private_data)
133 struct vm_device *dev = (struct vm_device *)private_data;
134 struct cons_state *state = (struct cons_state *)dev->private_data;
137 /* simply update the screen */
138 return screen_update(0, 0, SCREEN_SIZE, private_data);
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);
148 /* done with console update */
149 if (V3_TtyUpdate(state->tty) < 0) {
150 PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
154 last_offset = BYTES_PER_ROW * (NUM_ROWS - 1);
160 static struct v3_console_ops cons_ops = {
161 .update_screen = screen_update,
162 .update_cursor = cursor_update,
166 static struct v3_device_ops dev_ops = {
173 static int cons_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg)
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");
182 /* read configuration */
183 V3_ASSERT(frontend_cfg);
184 V3_ASSERT(frontend_tag);
189 state = (struct cons_state *)V3_Malloc(sizeof(struct cons_state));
191 state->frontend_dev = frontend;
194 /* open tty for screen display */
195 state->tty = V3_TtyOpen(ttypath, TTY_OPEN_MODE_READ | TTY_OPEN_MODE_WRITE);
197 PrintError("Could not open tty %s\n", ttypath);
202 /* allocate device */
203 struct vm_device *dev = v3_allocate_device(dev_id, &dev_ops, state);
206 /* attach device to virtual machine */
207 if (v3_attach_device(vm, dev) == -1) {
208 PrintError("Could not attach device %s\n", dev_id);
213 /* attach to front-end display adapter */
214 v3_console_register_cga(frontend, &cons_ops, dev);
219 device_register("CURSES_CONSOLE", cons_init)