From: Erik van der Kouwe Date: Wed, 14 Apr 2010 19:19:25 +0000 (-0500) Subject: add console hook support X-Git-Url: http://v3vee.org/palacios/gitweb/gitweb.cgi?p=palacios.git;a=commitdiff_plain;h=ddd9fd13627552b915753b06be997921cc904466 add console hook support --- diff --git a/Kconfig b/Kconfig index 3c9ccf7..a36c46b 100644 --- a/Kconfig +++ b/Kconfig @@ -45,6 +45,15 @@ config MAX_CPUS For uniprocessor environments, set this to 1 +config CONSOLE + bool "Include Console Support" + default n + help + Enable console support in Palacios + + + + config SOCKET bool "Include Network Socket Support" default n diff --git a/palacios/include/palacios/vmm_console.h b/palacios/include/palacios/vmm_console.h new file mode 100644 index 0000000..2b38c0d --- /dev/null +++ b/palacios/include/palacios/vmm_console.h @@ -0,0 +1,93 @@ +/* + * 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 + * Copyright (c) 2010, Erik van der Kouwe + * Copyright (c) 2010, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * Author: Erik van der Kouwe + * + * 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 + + +#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 diff --git a/palacios/src/devices/Kconfig b/palacios/src/devices/Kconfig index 8fc349c..30fb2b1 100644 --- a/palacios/src/devices/Kconfig +++ b/palacios/src/devices/Kconfig @@ -286,5 +286,13 @@ config TELNET_CONSOLE help Includes the virtual telnet console + +config CURSES_CONSOLE + bool "Curses Virtual Console" + default n + depends on CGA && !PASSTHROUGH_VIDEO + help + Includes the virtual curses console + endmenu diff --git a/palacios/src/devices/Makefile b/palacios/src/devices/Makefile index 1aeb3f4..b159c16 100644 --- a/palacios/src/devices/Makefile +++ b/palacios/src/devices/Makefile @@ -26,5 +26,6 @@ obj-$(CONFIG_NETDISK) += netdisk.o obj-$(CONFIG_CGA) += cga.o obj-$(CONFIG_TELNET_CONSOLE) += telnet_cons.o +obj-$(CONFIG_CURSES_CONSOLE) += curses_cons.o obj-$(CONFIG_PASSTHROUGH_PCI) += pci_passthrough.o diff --git a/palacios/src/devices/curses_cons.c b/palacios/src/devices/curses_cons.c new file mode 100644 index 0000000..b18b9d9 --- /dev/null +++ b/palacios/src/devices/curses_cons.c @@ -0,0 +1,223 @@ +/* + * 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 + * Copyright (c) 2009, Steven Jaconette + * Copyright (c) 2009, The V3VEE Project + * 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 +#include +#include +#include +#include +#include +#include + +#include + +#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) + diff --git a/palacios/src/palacios/Makefile b/palacios/src/palacios/Makefile index c669cd0..edd13a0 100644 --- a/palacios/src/palacios/Makefile +++ b/palacios/src/palacios/Makefile @@ -56,6 +56,7 @@ obj-$(CONFIG_VMX) += vmx.o \ obj-$(CONFIG_INSTRUMENT_VMM) += vmm_instrument.o obj-$(CONFIG_TELEMETRY) += vmm_telemetry.o obj-$(CONFIG_SOCKET) += vmm_socket.o +obj-$(CONFIG_CONSOLE) += vmm_console.o obj-$(CONFIG_VNET) += vmm_vnet.o obj-$(CONFIG_SYMBIOTIC) += vmm_sym_iface.o diff --git a/palacios/src/palacios/vmm_console.c b/palacios/src/palacios/vmm_console.c new file mode 100644 index 0000000..ef142b9 --- /dev/null +++ b/palacios/src/palacios/vmm_console.c @@ -0,0 +1,36 @@ +/* + * 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 + * Copyright (c) 2010, Erik van der Kouwe + * Copyright (c) 2010, The V3VEE Project + * All rights reserved. + * + * Author: Jack Lange + * Author: Erik van der Kouwe + * + * This is free software. You are permitted to use, + * redistribute, and modify it as specified in the file "V3VEE_LICENSE". + */ + + +#include +#include +#include +#include + + +struct v3_console_hooks * console_hooks = 0; + +void V3_Init_Console(struct v3_console_hooks * hooks) { + console_hooks = hooks; + PrintDebug("V3 console inited\n"); + + return; +}