--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2010, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2010, Erik van der Kouwe <vdkouwe@cs.vu.nl>
+ * Copyright (c) 2010, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ * Author: Erik van der Kouwe <vdkouwe@cs.vu.nl>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+#ifndef __VMM_CONSOLE_H__
+#define __VMM_CONSOLE_H__
+
+#include <palacios/vmm.h>
+
+
+#ifdef __V3VEE__
+
+#define V3_TtyOpen(path, mode) \
+ ({ \
+ extern struct v3_console_hooks *console_hooks; \
+ ((console_hooks) && (console_hooks)->tty_open) ? \
+ (console_hooks)->tty_open((path), (mode)) : NULL; \
+ })
+
+#define V3_TtyCursorSet(tty, x, y) \
+ ({ \
+ extern struct v3_console_hooks *console_hooks; \
+ ((console_hooks) && (console_hooks)->tty_cursor_set) ? \
+ (console_hooks)->tty_cursor_set((tty), (x), (y)) : -1; \
+ })
+
+#define V3_TtyCharacterSet(tty, x, y, c, style) \
+ ({ \
+ extern struct v3_console_hooks *console_hooks; \
+ ((console_hooks) && (console_hooks)->tty_character_set) ? \
+ (console_hooks)->tty_character_set((tty), (x), (y), (c), (style)) : -1; \
+ })
+
+#define V3_TtyScroll(tty, lines) \
+ ({ \
+ extern struct v3_console_hooks *console_hooks; \
+ ((console_hooks) && (console_hooks)->tty_scroll) ? \
+ (console_hooks)->tty_scroll((tty), (lines)) : -1; \
+ })
+
+#define V3_TtyUpdate(tty) \
+ ({ \
+ extern struct v3_console_hooks *console_hooks; \
+ ((console_hooks) && (console_hooks)->tty_update) ? \
+ (console_hooks)->tty_update((tty)) : -1; \
+ })
+
+#endif
+
+#define TTY_OPEN_MODE_READ (1 << 0)
+#define TTY_OPEN_MODE_WRITE (1 << 1)
+
+struct v3_console_hooks {
+ /* open console device, mode is a combination of TTY_OPEN_MODE_* flags */
+ void *(*tty_open)(const char *path, int mode);
+
+ /* set cursor position */
+ int (*tty_cursor_set)(void *tty, int x, int y);
+
+ /* output character c with specified style at (x, y) */
+ int (*tty_character_set)(void *tty, int x, int y, char c, unsigned char style);
+
+ /* scroll the console down the specified number of lines */
+ int (*tty_scroll)(void *tty, int lines);
+
+ /* force update of console display; all updates by above functions
+ * may be defferred until the next tty_update call
+ */
+ int (*tty_update)(void *tty);
+};
+
+
+extern void V3_Init_Console(struct v3_console_hooks * hooks);
+
+#endif
--- /dev/null
+/*
+ * This file is part of the Palacios Virtual Machine Monitor developed
+ * by the V3VEE Project with funding from the United States National
+ * Science Foundation and the Department of Energy.
+ *
+ * The V3VEE Project is a joint project between Northwestern University
+ * and the University of New Mexico. You can find out more at
+ * http://www.v3vee.org
+ *
+ * Copyright (c) 2009, Robert Deloatch <rtdeloatch@gmail.com>
+ * Copyright (c) 2009, Steven Jaconette <stevenjaconette2007@u.northwestern.edu>
+ * Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Erik van der Kouwe (vdkouwe@cs.vu.nl)
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+/* Interface between virtual video card and console */
+
+#include <palacios/vmm.h>
+#include <palacios/vmm_console.h>
+#include <palacios/vmm_dev_mgr.h>
+#include <palacios/vmm_sprintf.h>
+#include <palacios/vmm_host_events.h>
+#include <palacios/vmm_lock.h>
+#include <palacios/vmm_string.h>
+
+#include <devices/console.h>
+
+#define NUM_ROWS 25
+#define NUM_COLS 80
+#define BYTES_PER_COL 2
+#define BYTES_PER_ROW (NUM_COLS * BYTES_PER_COL)
+
+#define SCREEN_SIZE (BYTES_PER_ROW * NUM_ROWS)
+
+struct cons_state
+{
+ void *tty;
+ struct vm_device *frontend_dev;
+};
+
+static int screen_update(uint_t x, uint_t y, uint_t length, void *private_data);
+
+static uint_t last_offset;
+
+static int cursor_update(uint_t x, uint_t y, void *private_data)
+{
+ struct vm_device *dev = (struct vm_device *) private_data;
+ struct cons_state *state = (struct cons_state *) dev->private_data;
+ uint_t offset = (x * BYTES_PER_COL) + (y * BYTES_PER_ROW);
+ uint_t last_x, last_y;
+
+ /* unfortunately Palacios sometimes misses some writes,
+ * but if they are accompanied by a cursor move we may be able to
+ * detect this
+ */
+ if (offset < last_offset) last_offset = 0;
+ if (offset > last_offset) {
+ last_x = (last_offset % BYTES_PER_ROW) / BYTES_PER_COL;
+ last_y = last_offset / BYTES_PER_ROW;
+ screen_update(last_x, last_y, offset - last_offset, private_data);
+ }
+
+ /* adjust cursor */
+ if (V3_TtyCursorSet(state->tty, x, y) < 0) {
+ PrintError("V3_TtyCursorSet(0x%p, %d, %d) failed\n", state->tty, x, y);
+ return -1;
+ }
+
+ /* done with console update */
+ if (V3_TtyUpdate(state->tty) < 0) {
+ PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int screen_update(uint_t x, uint_t y, uint_t length, void *private_data)
+{
+ struct vm_device *dev = (struct vm_device *)private_data;
+ struct cons_state *state = (struct cons_state *)dev->private_data;
+ uint_t offset = (x * BYTES_PER_COL) + (y * BYTES_PER_ROW);
+ uint8_t fb_buf[length];
+ int i;
+ uint_t cur_x = x;
+ uint_t cur_y = y;
+
+ /* grab frame buffer */
+ memset(fb_buf, 0, length);
+ v3_cons_get_fb(state->frontend_dev, fb_buf, offset, length);
+
+ /* update the screen */
+ for (i = 0; i < length; i += 2)
+ {
+ uint_t col_index = i;
+ uint8_t col[2];
+
+ col[0] = fb_buf[col_index]; // Character
+ col[1] = fb_buf[col_index + 1]; // Attribute
+
+ /* update current character */
+ if (V3_TtyCharacterSet(state->tty, cur_x, cur_y, col[0], col[1]) < 0) {
+ PrintError("V3_TtyCursorSet(0x%p, %d, %d, %d, %d) failed\n",
+ state->tty, cur_x, cur_y, col[1], col[0]);
+ return -1;
+ }
+
+ // CAUTION: the order of these statements is critical
+ // cur_y depends on the previous value of cur_x
+ cur_y = cur_y + ((cur_x + 1) / NUM_COLS);
+ cur_x = (cur_x + 1) % NUM_COLS;
+ }
+
+ /* done with console update */
+ if (V3_TtyUpdate(state->tty) < 0) {
+ PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
+ return -1;
+ }
+
+ /* store offset to catch missing notifications */
+ last_offset = offset + length;
+
+ return 0;
+}
+
+static int scroll(int rows, void *private_data)
+{
+ struct vm_device *dev = (struct vm_device *)private_data;
+ struct cons_state *state = (struct cons_state *)dev->private_data;
+
+ if (rows < 0) {
+ /* simply update the screen */
+ return screen_update(0, 0, SCREEN_SIZE, private_data);
+ }
+
+ if (rows > 0) {
+ /* scroll requested number of lines*/
+ if (V3_TtyScroll(state->tty, rows) < 0) {
+ PrintError("V3_TtyScroll(0x%p, %u) failed\n", state->tty, rows);
+ return -1;
+ }
+
+ /* done with console update */
+ if (V3_TtyUpdate(state->tty) < 0) {
+ PrintError("V3_TtyUpdate(0x%p) failed\n", state->tty);
+ return -1;
+ }
+
+ last_offset = BYTES_PER_ROW * (NUM_ROWS - 1);
+ }
+
+ return 0;
+}
+
+static struct v3_console_ops cons_ops = {
+ .update_screen = screen_update,
+ .update_cursor = cursor_update,
+ .scroll = scroll,
+};
+
+static struct v3_device_ops dev_ops = {
+ .free = NULL,
+ .reset = NULL,
+ .start = NULL,
+ .stop = NULL,
+};
+
+static int cons_init(struct guest_info * vm, v3_cfg_tree_t * cfg)
+{
+ struct cons_state * state;
+ v3_cfg_tree_t * frontend_cfg;
+ const char *frontend_tag;
+ struct vm_device * frontend;
+ char *name, *ttypath;
+
+ /* read configuration */
+ frontend_cfg = v3_cfg_subtree(cfg, "frontend");
+ V3_ASSERT(frontend_cfg);
+ frontend_tag = v3_cfg_val(frontend_cfg, "tag");
+ V3_ASSERT(frontend_tag);
+ frontend = v3_find_dev(vm, frontend_tag);
+ V3_ASSERT(frontend);
+ name = v3_cfg_val(cfg, "name");
+
+ /* allocate state */
+ state = (struct cons_state *) V3_Malloc(sizeof(struct cons_state));
+ V3_ASSERT(state);
+ state->frontend_dev = frontend;
+ ttypath = v3_cfg_val(cfg, "tty");
+ V3_ASSERT(ttypath);
+
+ /* open tty for screen display */
+ state->tty = V3_TtyOpen(ttypath, TTY_OPEN_MODE_READ | TTY_OPEN_MODE_WRITE);
+ if (!state->tty) {
+ PrintError("Could not open tty %s\n", ttypath);
+ V3_Free(state);
+ return -1;
+ }
+
+ /* allocate device */
+ struct vm_device *dev = v3_allocate_device(name, &dev_ops, state);
+ V3_ASSERT(dev);
+
+ /* attach device to virtual machine */
+ if (v3_attach_device(vm, dev) == -1) {
+ PrintError("Could not attach device %s\n", name);
+ V3_Free(state);
+ return -1;
+ }
+
+ /* attach to front-end display adapter */
+ v3_console_register_cga(frontend, &cons_ops, dev);
+
+ return 0;
+}
+
+device_register("CURSES_CONSOLE", cons_init)
+