Compile with support for Intel VMX
+config FRAME_POINTER
+ bool "Compile with Frame pointers"
+ default n
+ help
+ Compiles the Palacios library with Frame pointers
+
config DEBUG_INFO
bool "Compile with Debug Information"
default n
menu "Debug configuration"
-config CONFIG_DEBUG_INFO
- bool "Compile with Debug information"
- default n
- help
- This adds the -g flag to the compilation flags
-
## Is unwind information useful
CPPFLAGS := $(V3_INCLUDE) -D__V3VEE__
-CFLAGS := -fno-stack-protector -Wall -Werror -mno-red-zone -fno-common
+CFLAGS := -fno-stack-protector -Wall -Werror -mno-red-zone -fno-common \
+ $(call cc-option, -Wno-unused-but-set-variable,)
endif
ifeq ($(KBUILD_EXTMOD),)
- ifneq ($(filter config %config,$(MAKECMDGOALS)),)
+ ifneq ($(filter %config,$(MAKECMDGOALS)),)
config-targets := 1
- ifneq ($(filter-out config %config,$(MAKECMDGOALS)),)
+ ifneq ($(filter-out %config,$(MAKECMDGOALS)),)
mixed-targets := 1
endif
endif
include $(srctree)/Makefile.$(ARCH)
export KBUILD_DEFCONFIG
-config %config: scripts_basic outputmakefile FORCE
+%config: scripts_basic outputmakefile FORCE
$(Q)mkdir -p palacios/include/config
$(Q)$(MAKE) $(build)=scripts/kconfig $@
# $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= .kernelrelease
ifdef V3_CONFIG_DEBUG_INFO
CFLAGS += -g
-else
-CFLAGS += -O
endif
$(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@)
# Modules
-/ %/: prepare scripts FORCE
+%/: prepare scripts FORCE
$(Q)$(MAKE) KBUILD_MODULES=$(if $(V3_CONFIG_MODULES),1) \
$(build)=$(build-dir)
%.ko: prepare scripts FORCE
v3vee-$(V3_CONFIG_KEYED_STREAMS) += iface-keyed-stream.o
v3vee-$(V3_CONFIG_HOST_DEVICE) += iface-host-dev.o
v3vee-$(V3_CONFIG_GRAPHICS_CONSOLE) += iface-graphics-console.o
+v3vee-$(V3_CONFIG_EXT_MACH_CHECK) += mcheck.o
v3vee-$(V3_CONFIG_VNET) += palacios-vnet.o \
palacios-vnet-ctrl.o \
for (i = 0; i < size; i++) {
- if (copy_from_user(&(event.scan_code), buf, 1)) {
+ if (copy_from_user(&(event.scan_code), buf + i, 1)) {
printk("Console Write fault\n");
return -EFAULT;
}
spin_lock_irqsave(&(cons->lock), flags);
- cons_fd = anon_inode_getfd("v3-cons", &cons_fops, cons, 0);
+ cons_fd = anon_inode_getfd("v3-cons", &cons_fops, cons, O_RDWR);
if (cons_fd < 0) {
printk("Error creating console inode\n");
#include "iface-stream.h"
-// This is going to need to be a lot bigger...
-#define STREAM_BUF_SIZE 1024
+// This is probably overkill
+#define STREAM_RING_LEN 4096
static struct list_head global_streams;
-struct stream_buffer {
+
+
+struct stream_state {
char name[STREAM_NAME_LEN];
- struct ringbuf * buf;
+
+ struct ringbuf * out_ring;
int connected;
struct v3_guest * guest;
struct list_head stream_node;
+
+ struct v3_stream * v3_stream;
};
// Currently just the list of open streams
-struct vm_stream_state {
+struct vm_global_streams {
struct list_head open_streams;
};
-static struct stream_buffer * find_stream_by_name(struct v3_guest * guest, const char * name) {
- struct stream_buffer * stream = NULL;
+
+
+
+static struct stream_state * find_stream_by_name(struct v3_guest * guest, const char * name) {
+ struct stream_state * stream = NULL;
struct list_head * stream_list = NULL;
- struct vm_stream_state * vm_state = NULL;
+ struct vm_global_streams * vm_state = NULL;
if (guest == NULL) {
stream_list = &global_streams;
+#define TMP_BUF_LEN 128
+
static ssize_t stream_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
- struct stream_buffer * stream = filp->private_data;
+ struct stream_state * stream = filp->private_data;
+ ssize_t bytes_read = 0;
+ ssize_t bytes_left = size;
+ unsigned long flags;
+ char tmp_buf[TMP_BUF_LEN];
+ ssize_t total_bytes_left = 0;
+
+ // memset(tmp_buf, 0, TMP_BUF_LEN);
+
+ while (bytes_left > 0) {
+ int tmp_len = (TMP_BUF_LEN > bytes_left) ? bytes_left : TMP_BUF_LEN;
+ int tmp_read = 0;
+
+ spin_lock_irqsave(&(stream->lock), flags);
+ tmp_read = ringbuf_read(stream->out_ring, tmp_buf, tmp_len);
+ spin_unlock_irqrestore(&(stream->lock), flags);
+
+ if (tmp_read == 0) {
+ // If userspace reads more than we have
+ break;
+ }
+
+ if (copy_to_user(buf + bytes_read, tmp_buf, tmp_read)) {
+ printk("Read Fault\n");
+ return -EFAULT;
+ }
+
+ bytes_left -= tmp_read;
+ bytes_read += tmp_read;
+ }
- wait_event_interruptible(stream->intr_queue, (ringbuf_data_len(stream->buf) != 0));
- return ringbuf_read(stream->buf, buf, size);
+ spin_lock_irqsave(&(stream->lock), flags);
+ total_bytes_left = ringbuf_data_len(stream->out_ring);
+ spin_unlock_irqrestore(&(stream->lock), flags);
+
+ if (total_bytes_left > 0) {
+ wake_up_interruptible(&(stream->intr_queue));
+ }
+
+ return bytes_read;
}
+static unsigned int
+stream_poll(struct file * filp, struct poll_table_struct * poll_tb) {
+ struct stream_state * stream = filp->private_data;
+ unsigned int mask = POLLIN | POLLRDNORM;
+ unsigned long flags;
+ int data_avail = 0;
+
+ poll_wait(filp, &(stream->intr_queue), poll_tb);
+
+ spin_lock_irqsave(&(stream->lock), flags);
+ data_avail = ringbuf_data_len(stream->out_ring);
+ spin_unlock_irqrestore(&(stream->lock), flags);
+
+ if (data_avail > 0) {
+ return mask;
+ }
+ return 0;
+
+}
+
+static ssize_t stream_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
+ struct stream_state * stream = filp->private_data;
+ char * kern_buf = NULL;
+ ssize_t bytes_written = 0;
+
+ kern_buf = kmalloc(size, GFP_KERNEL);
+
+ if (copy_from_user(kern_buf, buf, size)) {
+ printk("Stream Write Failed\n");
+ return -EFAULT;
+ };
+
+ bytes_written = stream->v3_stream->input(stream->v3_stream, kern_buf, size);
+
+ kfree(kern_buf);
+
+ return bytes_written;
+}
+
+
+static int stream_release(struct inode * i, struct file * filp) {
+ struct stream_state * stream = filp->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&(stream->lock), flags);
+ stream->connected = 0;
+ spin_unlock_irqrestore(&(stream->lock), flags);
+
+
+ return 0;
+
+}
static struct file_operations stream_fops = {
.read = stream_read,
- // .release = stream_close,
- // .poll = stream_poll,
+ .write = stream_write,
+ .release = stream_release,
+ .poll = stream_poll,
};
-static void * palacios_stream_open(const char * name, void * private_data) {
+static void * palacios_stream_open(struct v3_stream * v3_stream, const char * name, void * private_data) {
struct v3_guest * guest = (struct v3_guest *)private_data;
- struct stream_buffer * stream = NULL;
- struct vm_stream_state * vm_state = NULL;
+ struct stream_state * stream = NULL;
+ struct vm_global_streams * vm_state = NULL;
if (guest != NULL) {
vm_state = get_vm_ext_data(guest, "STREAM_INTERFACE");
return NULL;
}
- stream = kmalloc(sizeof(struct stream_buffer), GFP_KERNEL);
-
- stream->buf = create_ringbuf(STREAM_BUF_SIZE);
+ stream = kmalloc(sizeof(struct stream_state), GFP_KERNEL);
+ memset(stream, 0, sizeof(struct stream_state));
+
+ stream->out_ring = create_ringbuf(STREAM_RING_LEN);
+ stream->v3_stream = v3_stream;
stream->guest = guest;
+ stream->connected = 0;
strncpy(stream->name, name, STREAM_NAME_LEN - 1);
}
-static int palacios_stream_write(void * stream_ptr, char * buf, int len) {
- struct stream_buffer * stream = (struct stream_buffer *)stream_ptr;
- int ret = 0;
+static uint64_t palacios_stream_output(struct v3_stream * v3_stream, char * buf, int len) {
+ struct stream_state * stream = (struct stream_state *)v3_stream->host_stream_data;
+ int bytes_written = 0;
+ unsigned long flags;
+
- ret = ringbuf_write(stream->buf, buf, len);
+ if (stream->connected == 0) {
+ return 0;
+ }
+
+ while (bytes_written < len) {
+ spin_lock_irqsave(&(stream->lock), flags);
+ bytes_written += ringbuf_write(stream->out_ring, buf + bytes_written, len - bytes_written);
+ spin_unlock_irqrestore(&(stream->lock), flags);
- if (ret > 0) {
wake_up_interruptible(&(stream->intr_queue));
+
+ if (bytes_written < len) {
+ // not enough space in ringbuffer, activate user space to drain it
+ schedule();
+ }
}
- return ret;
+
+ return bytes_written;
}
-static void palacios_stream_close(void * stream_ptr) {
- struct stream_buffer * stream = (struct stream_buffer *)stream_ptr;
+static void palacios_stream_close(struct v3_stream * v3_stream) {
+ struct stream_state * stream = (struct stream_state *)v3_stream->host_stream_data;
- free_ringbuf(stream->buf);
+ free_ringbuf(stream->out_ring);
list_del(&(stream->stream_node));
kfree(stream);
static struct v3_stream_hooks palacios_stream_hooks = {
.open = palacios_stream_open,
- .write = palacios_stream_write,
+ .output = palacios_stream_output,
.close = palacios_stream_close,
};
static int stream_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data) {
void __user * argp = (void __user *)arg;
- struct stream_buffer * stream = NULL;
+ struct stream_state * stream = NULL;
int stream_fd = 0;
char name[STREAM_NAME_LEN];
unsigned long flags = 0;
}
- stream_fd = anon_inode_getfd("v3-stream", &stream_fops, stream, 0);
+ stream_fd = anon_inode_getfd("v3-stream", &stream_fops, stream, O_RDWR);
if (stream_fd < 0) {
printk("Error creating stream inode for (%s)\n", name);
static int guest_stream_init(struct v3_guest * guest, void ** vm_data) {
- struct vm_stream_state * state = kmalloc(sizeof(struct vm_stream_state), GFP_KERNEL);
+ struct vm_global_streams * state = kmalloc(sizeof(struct vm_global_streams), GFP_KERNEL);
INIT_LIST_HEAD(&(state->open_streams));
*vm_data = state;
-
add_guest_ctrl(guest, V3_VM_STREAM_CONNECT, stream_connect, state);
return 0;
static int guest_stream_deinit(struct v3_guest * guest, void * vm_data) {
- struct vm_stream_state * state = vm_data;
+ struct vm_global_streams * state = vm_data;
if (!list_empty(&(state->open_streams))) {
printk("Error shutting down VM with open streams\n");
}
--- /dev/null
+/*
+ * DebugFS interface
+ * (c) Patrick Bridges and Philip Soltero, 2011
+ */
+
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+#include <interfaces/vmm_mcheck.h>
+
+#include "palacios.h"
+#include "vm.h"
+#include "linux-exts.h"
+
+#define SCRUBBER_MCE 0x1
+#define V3_VM_INJECT_SCRUBBER_MCE (10224+20)
+
+static int inject_mce(struct v3_guest * guest, unsigned int cmd, unsigned long arg,
+ void * priv_data)
+{
+ unsigned long type = (unsigned long)priv_data;
+ switch ( type ) {
+ case SCRUBBER_MCE:
+ return v3_mcheck_inject_scrubber_mce((struct v3_vm_info *)guest->v3_ctx, 0, arg);
+ break;
+ default:
+ // TODO: How to print an error in the host OS?
+ //PrintError("Injection of unknown machine check type %lu requested.\n", type);
+ return -1;
+ break;
+ }
+}
+
+static int guest_init(struct v3_guest * guest, void ** vm_data) {
+
+ add_guest_ctrl(guest, V3_VM_INJECT_SCRUBBER_MCE, inject_mce, (void *)SCRUBBER_MCE);
+ return 0;
+}
+
+static int guest_deinit(struct v3_guest * guest, void * vm_data) {
+
+ return 0;
+}
+
+
+struct linux_ext mcheck_ext = {
+ .name = "MACHINE CHECK",
+ .init = NULL,
+ .deinit = NULL,
+ .guest_init = guest_init,
+ .guest_deinit = guest_deinit
+};
+
+
+register_extension(&mcheck_ext);
start = ((alignment - (pool.base_addr % alignment)) >> 12);
}
- printk("\t Start idx %d (base_addr=%llu)\n", start, (u64)pool.base_addr);
+ printk("\t Start idx %d (base_addr=%p)\n", start, (void *)(u64)pool.base_addr);
for (i = start; i < (pool.num_pages - num_pages); i += step) {
if (get_page_bit(i) == 0) {
palacios_alloc(unsigned int size) {
void * addr = NULL;
- addr = kmalloc(size, GFP_KERNEL);
+ if (irqs_disabled()) {
+ addr = kmalloc(size, GFP_ATOMIC);
+ } else {
+ addr = kmalloc(size, GFP_KERNEL);
+ }
mallocs++;
+
return addr;
}
printk("palacios_init starting - calling init_v3\n");
- Init_V3(&palacios_os_hooks, nr_cpu_ids);
+ Init_V3(&palacios_os_hooks, num_online_cpus());
return 0;
vnet_brg_s.stats.pkt_to_vmm ++;
- return v3_vnet_send_pkt(&pkt, NULL, 1);
+ return v3_vnet_send_pkt(&pkt, NULL);
}
return -1;
}
- vnet_brg_s.serv_thread = kthread_run(_rx_server, NULL, "vnet-server");
+ vnet_brg_s.serv_thread = kthread_run(_rx_server, NULL, "vnet_brgd");
bridge_ops.input = bridge_send_pkt;
bridge_ops.poll = NULL;
#define V3_VM_CONSOLE_CONNECT 20
#define V3_VM_STOP 22
+#define V3_VM_PAUSE 23
+#define V3_VM_CONTINUE 24
+
#define V3_VM_INSPECT 30
#include <linux/errno.h>
#include <linux/preempt.h>
#include <linux/sched.h>
+#include <linux/slab.h>
#include "util-hashtable.h"
#include <linux/poll.h>
#include <linux/anon_inodes.h>
#include <linux/sched.h>
-
+#include <linux/vmalloc.h>
#include <linux/file.h>
#include <linux/spinlock.h>
#include <linux/rbtree.h>
switch (ioctl) {
case V3_VM_STOP: {
- printk("Stopping VM\n");
+ printk("Stopping VM (%s)\n", guest->name);
stop_palacios_vm(guest);
break;
}
+ case V3_VM_PAUSE: {
+ printk("Pausing VM (%s)\n", guest->name);
+ v3_pause_vm(guest->v3_ctx);
+ break;
+ }
+ case V3_VM_CONTINUE: {
+ printk("Continuing VM (%s)\n", guest->name);
+ v3_continue_vm(guest->v3_ctx);
+ break;
+ }
default: {
struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
cdev_del(&(guest->cdev));
- kfree(guest->img);
+ vfree(guest->img);
kfree(guest);
return 0;
-all: v3_ctrl v3_stop v3_cons v3_mem v3_monitor v3_serial v3_net v3_user_host_dev_example v3_os_debug v3_user_keyed_stream_example v3_user_keyed_stream_file
+all: v3_ctrl v3_stop v3_cons v3_mem v3_monitor v3_stream v3_user_host_dev_example v3_os_debug v3_user_keyed_stream_example v3_user_keyed_stream_file
v3_cons : v3_cons.c v3_ctrl.h
gcc -static v3_cons.c -o v3_cons -lcurses
-v3_serial : v3_serial.c v3_ctrl.h
- gcc -static v3_serial.c -pthread -o v3_serial
+v3_stream : v3_stream.c v3_ctrl.h
+ gcc -static v3_stream.c -o v3_stream
v3_monitor : v3_cons.c v3_ctrl.h
gcc -static v3_monitor.c -o v3_monitor
-v3_net : v3_net.c v3_ctrl.h
- gcc -static v3_net.c -o v3_net
-
v3_user_host_dev_example: v3_user_host_dev_example.c v3_user_host_dev.h v3_user_host_dev.c
gcc -static -I../linux_module v3_user_host_dev_example.c v3_user_host_dev.c -o v3_user_host_dev_example
v3_user_keyed_stream_file: v3_user_keyed_stream_file.c v3_user_keyed_stream.h v3_user_keyed_stream.c
gcc -static -I../linux_module v3_user_keyed_stream_file.c v3_user_keyed_stream.c -o v3_user_keyed_stream_file
-
-
+v3_inject_ecc_scrubber_mce: v3_inject_ecc_scrubber_mce.c
+ gcc -static -I../linux_module v3_inject_ecc_scrubber_mce.c -o v3_inject_ecc_scrubber_mce
clean:
- rm -f v3_ctrl v3_cons v3_mem v3_monitor v3_serial v3_net v3_user_host_dev_example v3_os_debug v3_user_keyed_stream_example v3_user_keyed_stream_file
+ rm -f v3_ctrl v3_cons v3_mem v3_monitor v3_stream v3_user_host_dev_example v3_os_debug v3_user_keyed_stream_example v3_user_keyed_stream_file
--- /dev/null
+/*
+ * V3 Console utility
+ * Taken from Palacios console display in MINIX ( by Erik Van der Kouwe )
+ * (c) Jack lange, 2010
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <assert.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <curses.h>
+#include <termios.h>
+#include <linux/kd.h>
+#include <linux/keyboard.h>
+
+#include "v3_ctrl.h"
+
+static int use_curses = 0;
+static int debug_enable = 1;
+
+
+typedef enum { CONSOLE_CURS_SET = 1,
+ CONSOLE_CHAR_SET = 2,
+ CONSOLE_SCROLL = 3,
+ CONSOLE_UPDATE = 4,
+ CONSOLE_RESOLUTION = 5 } console_op_t;
+
+
+
+static struct {
+ WINDOW * win;
+ int x;
+ int y;
+ int rows;
+ int cols;
+ struct termios termios_old;
+ unsigned char old_kbd_mode;
+} console;
+
+
+struct cursor_msg {
+ int x;
+ int y;
+} __attribute__((packed));
+
+struct character_msg {
+ int x;
+ int y;
+ char c;
+ unsigned char style;
+} __attribute__((packed));
+
+struct scroll_msg {
+ int lines;
+} __attribute__((packed));
+
+struct resolution_msg {
+ int cols;
+ int rows;
+} __attribute__((packed));
+
+
+struct cons_msg {
+ unsigned char op;
+ union {
+ struct cursor_msg cursor;
+ struct character_msg character;
+ struct scroll_msg scroll;
+ struct resolution_msg resolution;
+ };
+} __attribute__((packed));
+
+
+
+
+static int handle_char_set(struct character_msg * msg) {
+ char c = msg->c;
+
+ if (debug_enable) {
+ fprintf(stderr, "setting char (%c), at (x=%d, y=%d)\n", c, msg->x, msg->y);
+ }
+
+ if (c == 0) {
+ c = ' ';
+ }
+
+
+ if ((c < ' ') || (c >= 127)) {
+ fprintf(stderr, "unexpected control character %d\n", c);
+ c = '?';
+ }
+
+ if (use_curses) {
+ /* clip whatever falls outside the visible area to avoid errors */
+ if ((msg->x < 0) || (msg->y < 0) ||
+ (msg->x > console.win->_maxx) ||
+ (msg->y > console.win->_maxy)) {
+
+ fprintf(stderr, "Char out of range (x=%d,y=%d) MAX:(x=%d,y=%d)\n",
+ msg->x, msg->y, console.win->_maxx, console.win->_maxy);
+ return -1;
+ }
+
+ if ((msg->x == console.win->_maxx) &&
+ (msg->y == console.win->_maxy)) {
+ return -1;
+ }
+
+ mvwaddch(console.win, msg->y, msg->x, c);
+
+ } else {
+ //stdout text display
+ while (console.y < msg->y) {
+ printf("\n");
+ console.x = 0;
+ console.y++;
+ }
+
+ while (console.x < msg->x) {
+ printf(" ");
+ console.x++;
+ }
+
+ printf("%c", c);
+ console.x++;
+
+ assert(console.x <= console.cols);
+
+ if (console.x == console.cols) {
+ printf("\n");
+ console.x = 0;
+ console.y++;
+ }
+ }
+
+ return 0;
+}
+
+int handle_curs_set(struct cursor_msg * msg) {
+ if (debug_enable) {
+ fprintf(stderr, "cursor set: (x=%d, y=%d)\n", msg->x, msg->y);
+ }
+
+ if (use_curses) {
+ /* nothing to do now, cursor is set before update to make sure it isn't
+ * affected by character_set
+ */
+
+ console.x = msg->x;
+ console.y = msg->y;
+ }
+
+ return 0;
+}
+
+
+int handle_scroll(struct scroll_msg * msg) {
+ int lines = msg->lines;
+
+ if (debug_enable) {
+ fprintf(stderr, "scroll: %d lines\n", lines);
+ }
+
+
+ assert(lines >= 0);
+
+ if (use_curses) {
+ while (lines > 0) {
+ scroll(console.win);
+ lines--;
+ }
+ } else {
+ console.y -= lines;
+ }
+}
+
+int handle_text_resolution(struct resolution_msg * msg) {
+ if (debug_enable) {
+ fprintf(stderr, "text resolution: rows=%d, cols=%d\n", msg->rows, msg->cols);
+ }
+
+
+ console.rows = msg->rows;
+ console.cols = msg->cols;
+
+ return 0;
+}
+
+int handle_update( void ) {
+ if (debug_enable) {
+ fprintf(stderr, "update\n");
+ }
+
+ if (use_curses) {
+
+ if ( (console.x >= 0) && (console.y >= 0) &&
+ (console.x <= console.win->_maxx) &&
+ (console.y <= console.win->_maxy) ) {
+
+ wmove(console.win, console.y, console.x);
+
+ }
+
+ wrefresh(console.win);
+ } else {
+ fflush(stdout);
+ }
+}
+
+
+int handle_console_msg(int cons_fd) {
+ int ret = 0;
+ struct cons_msg msg;
+
+ ret = read(cons_fd, &msg, sizeof(struct cons_msg));
+
+ switch (msg.op) {
+ case CONSOLE_CURS_SET:
+ // printf("Console cursor set (x=%d, y=%d)\n", msg.cursor.x, msg.cursor.y);
+ handle_curs_set(&(msg.cursor));
+ break;
+ case CONSOLE_CHAR_SET:
+ handle_char_set(&(msg.character));
+ /* printf("Console character set (x=%d, y=%d, c=%c, style=%c)\n",
+ msg.character.x, msg.character.y, msg.character.c, msg.character.style);*/
+ break;
+ case CONSOLE_SCROLL:
+ // printf("Console scroll (lines=%d)\n", msg.scroll.lines);
+ handle_scroll(&(msg.scroll));
+ break;
+ case CONSOLE_UPDATE:
+ // printf("Console update\n");
+ handle_update();
+ break;
+ case CONSOLE_RESOLUTION:
+ handle_text_resolution(&(msg.resolution));
+ break;
+ default:
+ printf("Invalid console message operation (%d)\n", msg.op);
+ break;
+ }
+
+ return 0;
+}
+
+
+int send_key(int cons_fd, char scan_code) {
+
+ return 0;
+}
+
+
+
+void handle_exit(void) {
+ fprintf(stderr, "Exiting from console terminal\n");
+
+ if (use_curses) {
+ endwin();
+ }
+
+ // tcsetattr(STDIN_FILENO, TCSANOW, &console.termios_old);
+
+ // ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE);
+}
+
+
+#define NO_KEY { 0, 0 }
+
+struct key_code {
+ unsigned char scan_code;
+ unsigned char capital;
+};
+
+static const struct key_code ascii_to_key_code[] = { // ASCII Value Serves as Index
+ NO_KEY, NO_KEY, NO_KEY, NO_KEY, // 0x00 - 0x03
+ NO_KEY, NO_KEY, NO_KEY, NO_KEY, // 0x04 - 0x07
+ { 0x0E, 0 }, { 0x0F, 0 }, { 0x1C, 0 }, NO_KEY, // 0x08 - 0x0B
+ NO_KEY, { 0x1C, 0 }, NO_KEY, NO_KEY, // 0x0C - 0x0F
+ NO_KEY, NO_KEY, NO_KEY, NO_KEY, // 0x10 - 0x13
+ NO_KEY, NO_KEY, NO_KEY, NO_KEY, // 0x14 - 0x17
+ NO_KEY, NO_KEY, NO_KEY, { 0x01, 0 }, // 0x18 - 0x1B
+ NO_KEY, NO_KEY, NO_KEY, NO_KEY, // 0x1C - 0x1F
+ { 0x39, 0 }, { 0x02, 1 }, { 0x28, 1 }, { 0x04, 1 }, // 0x20 - 0x23
+ { 0x05, 1 }, { 0x06, 1 }, { 0x08, 1 }, { 0x28, 0 }, // 0x24 - 0x27
+ { 0x0A, 1 }, { 0x0B, 1 }, { 0x09, 1 }, { 0x0D, 1 }, // 0x28 - 0x2B
+ { 0x33, 0 }, { 0x0C, 0 }, { 0x34, 0 }, { 0x35, 0 }, // 0x2C - 0x2F
+ { 0x0B, 0 }, { 0x02, 0 }, { 0x03, 0 }, { 0x04, 0 }, // 0x30 - 0x33
+ { 0x05, 0 }, { 0x06, 0 }, { 0x07, 0 }, { 0x08, 0 }, // 0x34 - 0x37
+ { 0x09, 0 }, { 0x0A, 0 }, { 0x27, 1 }, { 0x27, 0 }, // 0x38 - 0x3B
+ { 0x33, 1 }, { 0x0D, 0 }, { 0x34, 1 }, { 0x35, 1 }, // 0x3C - 0x3F
+ { 0x03, 1 }, { 0x1E, 1 }, { 0x30, 1 }, { 0x2E, 1 }, // 0x40 - 0x43
+ { 0x20, 1 }, { 0x12, 1 }, { 0x21, 1 }, { 0x22, 1 }, // 0x44 - 0x47
+ { 0x23, 1 }, { 0x17, 1 }, { 0x24, 1 }, { 0x25, 1 }, // 0x48 - 0x4B
+ { 0x26, 1 }, { 0x32, 1 }, { 0x31, 1 }, { 0x18, 1 }, // 0x4C - 0x4F
+ { 0x19, 1 }, { 0x10, 1 }, { 0x13, 1 }, { 0x1F, 1 }, // 0x50 - 0x53
+ { 0x14, 1 }, { 0x16, 1 }, { 0x2F, 1 }, { 0x11, 1 }, // 0x54 - 0x57
+ { 0x2D, 1 }, { 0x15, 1 }, { 0x2C, 1 }, { 0x1A, 0 }, // 0x58 - 0x5B
+ { 0x2B, 0 }, { 0x1B, 0 }, { 0x07, 1 }, { 0x0C, 1 }, // 0x5C - 0x5F
+ { 0x29, 0 }, { 0x1E, 0 }, { 0x30, 0 }, { 0x2E, 0 }, // 0x60 - 0x63
+ { 0x20, 0 }, { 0x12, 0 }, { 0x21, 0 }, { 0x22, 0 }, // 0x64 - 0x67
+ { 0x23, 0 }, { 0x17, 0 }, { 0x24, 0 }, { 0x25, 0 }, // 0x68 - 0x6B
+ { 0x26, 0 }, { 0x32, 0 }, { 0x31, 0 }, { 0x18, 0 }, // 0x6C - 0x6F
+ { 0x19, 0 }, { 0x10, 0 }, { 0x13, 0 }, { 0x1F, 0 }, // 0x70 - 0x73
+ { 0x14, 0 }, { 0x16, 0 }, { 0x2F, 0 }, { 0x11, 0 }, // 0x74 - 0x77
+ { 0x2D, 0 }, { 0x15, 0 }, { 0x2C, 0 }, { 0x1A, 1 }, // 0x78 - 0x7B
+ { 0x2B, 1 }, { 0x1B, 1 }, { 0x29, 1 }, { 0x0E, 0 } // 0x7C - 0x7F
+};
+
+
+
+#define writeit(fd,c) do { fprintf(stderr,"scancode 0x%x\n",(c)); if (write((fd),&(c),1)!=1) { return -1; } } while (0)
+
+int send_char_to_palacios_as_scancodes(int fd, unsigned char c)
+{
+ unsigned char sc;
+
+ fprintf(stderr,"key '%c'\n",c);
+
+ if (c<0x80) {
+ struct key_code k = ascii_to_key_code[c];
+
+ if (k.scan_code==0 && k.capital==0) {
+ fprintf(stderr,"Cannot send key '%c' to palacios as it maps to no scancode\n",c);
+ } else {
+ if (k.capital) {
+ //shift down
+ sc = 0x2a ; // left shift down
+ writeit(fd,sc);
+ }
+
+
+ sc = k.scan_code;
+
+ writeit(fd,sc); // key down
+
+ sc |= 0x80; // key up
+
+ writeit(fd,sc);
+
+ if (k.capital) {
+ sc = 0x2a | 0x80;
+ writeit(fd,sc);
+ }
+ }
+
+ } else {
+
+
+ fprintf(stderr,"Cannot send key '%c' to palacios because it is >=0x80\n",c);
+
+/* switch (key) { */
+/* case 0xffe1: //left shift */
+/* scancode = 0x2a; */
+/* break; */
+
+/* case 0xffe2: //right shift */
+/* scancode = 0x36; */
+/* break; */
+
+/* case 0xffe3: //left ctrl */
+/* case 0xffe4: //right ctrl */
+/* scancode = 0x1d; // translated as left ctrl */
+/* break; */
+
+/* case 0xffe7: //left meta */
+/* case 0xffe8: //right meta */
+/* case 0xffe9: //left alt */
+/* case 0xffea: //right alt */
+/* scancode = 0x38; // translated as a left alt */
+/* break; */
+
+/* case 0xff08: // backspace */
+/* scancode = 0x0e; */
+/* break; */
+
+/* case 0xff09: // tab */
+/* scancode = 0x0f; */
+/* break; */
+
+/* case 0xff0d: // return */
+/* scancode = 0x1c; */
+/* break; */
+
+/* case 0xff1b: // escape */
+/* scancode = 0x01; */
+/* break; */
+
+/* case 0xff63: // insert */
+/* scancode = 0x52; */
+/* break; */
+
+/* case 0xffff: // delete */
+/* scancode = 0x53; */
+/* break; */
+
+/* case 0xff50: // home */
+/* scancode = 0x47; */
+/* break; */
+
+/* case 0xff57: // end */
+/* scancode = 0x4f; */
+/* break; */
+
+/* case 0xff55: // pageup */
+/* scancode = 0x49; */
+/* break; */
+
+/* case 0xff56: // pagedown */
+/* scancode = 0x51; */
+/* break; */
+
+/* case 0xff51: // left */
+/* scancode = 0x4b; */
+/* break; */
+
+/* case 0xff52: // up */
+/* scancode = 0x48; */
+/* break; */
+
+/* case 0xff53: // right */
+/* scancode = 0x4d; */
+/* break; */
+
+/* case 0xff54: // down */
+/* scancode = 0x50; */
+/* break; */
+
+/* case 0xffbe: // f1 */
+/* scancode = 0x3b; */
+/* break; */
+/* case 0xffbf: // f2 */
+/* scancode = 0x3c; */
+/* break; */
+/* case 0xffc0: // f3 */
+/* scancode = 0x3d; */
+/* break; */
+/* case 0xffc1: // f4 */
+/* scancode = 0x3e; */
+/* break; */
+/* case 0xffc2: // f5 */
+/* scancode = 0x3f; */
+/* break; */
+/* case 0xffc3: // f6 */
+/* scancode = 0x40; */
+/* break; */
+/* case 0xffc4: // f7 */
+/* scancode = 0x41; */
+/* break; */
+/* case 0xffc5: // f8 */
+/* scancode = 0x42; */
+/* break; */
+/* case 0xffc6: // f9 */
+/* scancode = 0x43; */
+/* break; */
+/* case 0xffc7: // f10 */
+/* scancode = 0x44; */
+/* break; */
+/* case 0xffc8: // f11 */
+/* scancode = 0x57; */
+/* break; */
+/* case 0xffc9: // f12 */
+/* scancode = 0x58; */
+/* break; */
+
+
+/* default: */
+/* scancode = 0; */
+/* fprintf(stderr,"Ignoring key 0x%x (down=%d)\n", key, down); */
+/* } */
+/* } */
+
+/* if (scancode==0) { */
+/* return 0; */
+/* } */
+
+
+/* return scancode; */
+
+ }
+ return 0;
+}
+
+int main(int argc, char* argv[]) {
+ int vm_fd;
+ int cons_fd;
+ char * vm_dev = NULL;
+ struct termios termios;
+
+ use_curses = 1;
+
+ if (argc < 2) {
+ printf("Usage: ./v3_cons <vm_device>\n");
+ return -1;
+ }
+
+ vm_dev = argv[1];
+
+
+
+ vm_fd = open(vm_dev, O_RDONLY);
+
+ if (vm_fd == -1) {
+ printf("Error opening VM device: %s\n", vm_dev);
+ return -1;
+ }
+
+ cons_fd = ioctl(vm_fd, V3_VM_CONSOLE_CONNECT, NULL);
+
+ /* Close the file descriptor. */
+ close(vm_fd);
+
+ if (cons_fd < 0) {
+ printf("Error opening stream Console\n");
+ return -1;
+ }
+
+ tcgetattr(STDIN_FILENO, &console.termios_old);
+ atexit(handle_exit);
+
+ console.x = 0;
+ console.y = 0;
+
+
+ if (use_curses) {
+ gettmode();
+ console.win = initscr();
+
+ if (console.win == NULL) {
+ fprintf(stderr, "Error initialization curses screen\n");
+ exit(-1);
+ }
+
+ scrollok(console.win, 1);
+ }
+
+ /*
+ termios = console.termios_old;
+ termios.c_iflag &= ~(BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR);
+ termios.c_iflag &= ~(INLCR | INPCK | ISTRIP | IXOFF | IXON | PARMRK);
+ //termios.c_iflag &= ~(ICRNL | INLCR );
+
+ // termios.c_iflag |= SCANCODES;
+ // termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
+ //termios.c_lflag &= ~(ICANON | IEXTEN | ISIG | NOFLSH);
+ termios.c_lflag &= ~(ICANON | ECHO);
+
+ termios.c_cc[VMIN] = 1;
+ termios.c_cc[VTIME] = 0;
+
+ tcflush(STDIN_FILENO, TCIFLUSH);
+ tcsetattr(STDIN_FILENO, TCSANOW, &termios);
+ */
+
+ raw();
+ cbreak();
+ noecho();
+ keypad(console.win, TRUE);
+
+ //ioctl(STDIN_FILENO, KDSKBMODE, K_RAW);
+
+ while (1) {
+ int ret;
+ int bytes_read = 0;
+ fd_set rset;
+
+ FD_ZERO(&rset);
+ FD_SET(cons_fd, &rset);
+ FD_SET(STDIN_FILENO, &rset);
+
+ ret = select(cons_fd + 1, &rset, NULL, NULL, NULL);
+
+ // printf("Returned from select...\n");
+
+ if (ret == 0) {
+ continue;
+ } else if (ret == -1) {
+ perror("Select returned error...\n");
+ return -1;
+ }
+
+ if (FD_ISSET(cons_fd, &rset)) {
+ if (handle_console_msg(cons_fd) == -1) {
+ printf("Console Error\n");
+ return -1;
+ }
+ }
+
+ if (FD_ISSET(STDIN_FILENO, &rset)) {
+ unsigned char key = getch();
+
+ if (key == '\\') { // ESC
+ break;
+ } else if (key == '`') {
+ unsigned char sc = 0x44; // F10
+ writeit(cons_fd,sc);
+ sc |= 0x80;
+ writeit(cons_fd,sc);
+ }else {
+ if (send_char_to_palacios_as_scancodes(cons_fd,key)) {
+ fprintf(stderr, "Error sendign key to console\n");
+ return -1;
+ }
+ }
+
+ }
+ }
+
+ close(cons_fd);
+
+ return 0;
+}
+
+
--- /dev/null
+/*
+ * V3 ECC DRAM Scrubber MCE
+ * (c) Philip Soltero, 2010
+ */
+
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#define V3_VM_INJECT_SCRUBBER_MCE (10224+20)
+
+int main(int argc, char * argv[]) {
+ char * end_ptr;
+ char * vm_device;
+ unsigned int cpu;
+ uint64_t address;
+ int v3_fd = 0;
+
+ if (argc <= 3) {
+ fprintf(stderr, "Usage: v3_inject_ecc_scrubber_mce <vm_device> <cpu> <hex address>\n");
+ return -1;
+ }
+
+ vm_device = argv[1];
+
+ cpu = strtol(argv[2], &end_ptr, 10);
+ if (strcmp(end_ptr, "\0") != 0) {
+ fprintf(stderr, "The specified cpu is not a valid integer '%s', in particular '%s'.\n", argv[2], end_ptr);
+ return -1;
+ }
+
+ address = strtoll(argv[3], &end_ptr, 16);
+ if (strcmp(end_ptr, "\0") != 0) {
+ fprintf(stderr, "The specified address is not a valid integer '%s', in particular '%s'.\n", argv[3], end_ptr);
+ return -1;
+ }
+
+ v3_fd = open(vm_device, O_RDONLY);
+
+ if (v3_fd == -1) {
+ fprintf(stderr, "Error opening V3Vee control device.\n");
+ return -1;
+ }
+
+ ioctl(v3_fd, V3_VM_INJECT_SCRUBBER_MCE, address);
+
+ /* Close the file descriptor. */
+ close(v3_fd);
+
+ return 0;
+}
unsigned char * bitmap = NULL;
int num_blocks = 0;
int reg_start = 0;
-
+ int mem_ready = 0;
if (argc != 2) {
printf("Usage: v3_mem <memory size (MB)>\n");
}
+ while (!mem_ready) {
- /* Scan bitmap for enough consecutive space */
- {
- // num_blocks: The number of blocks we need to find
- // bitmap: bitmap of blocks (1 == allocatable)
- // bitmap_entries: number of blocks in the system/number of bits in bitmap
- // reg_start: The block index where our allocation will start
- int i = 0;
- int run_len = 0;
+ /* Scan bitmap for enough consecutive space */
+ {
+ // num_blocks: The number of blocks we need to find
+ // bitmap: bitmap of blocks (1 == allocatable)
+ // bitmap_entries: number of blocks in the system/number of bits in bitmap
+ // reg_start: The block index where our allocation will start
+
+ int i = 0;
+ int run_len = 0;
+
+ for (i = 0; i < bitmap_entries; i++) {
+ int i_major = i / 8;
+ int i_minor = i % 8;
+
+
+ if (!(bitmap[i_major] & (0x1 << i_minor))) {
+ reg_start = i + 1; // skip the region start to next entry
+ run_len = 0;
+ continue;
+ }
+
+ run_len++;
+
+ if (run_len >= num_blocks) {
+ break;
+ }
+ }
- for (i = 0; i < bitmap_entries; i++) {
- int i_major = i / 8;
- int i_minor = i % 8;
+
+ if (run_len < num_blocks) {
+ fprintf(stderr, "Could not find enough consecutive memory blocks... (found %d)\n", run_len);
+ return -1;
+ }
+ }
+
+ /* Offline memory blocks starting at reg_start */
+ {
+ int i = 0;
- if (!(bitmap[i_major] & (0x1 << i_minor))) {
- reg_start = i + 1; // skip the region start to next entry
- run_len = 0;
- continue;
- }
+ for (i = 0; i < num_blocks; i++) {
+ FILE * block_file = NULL;
+ char fname[256];
+
+ memset(fname, 0, 256);
+
+ snprintf(fname, 256, "%smemory%d/state", SYS_PATH, i + reg_start);
+
+ block_file = fopen(fname, "r+");
+
+ if (block_file == NULL) {
+ perror("Could not open block file");
+ return -1;
+ }
- run_len++;
- if (run_len >= num_blocks) {
- break;
+ printf("Offlining block %d (%s)\n", i + reg_start, fname);
+ fprintf(block_file, "offline\n");
+
+ fclose(block_file);
}
}
- free(bitmap);
-
- if (run_len < num_blocks) {
- fprintf(stderr, "Could not find enough consecutive memory blocks... (found %d)\n", run_len);
- return -1;
- }
- }
-
- /* Offline memory blocks starting at reg_start */
- {
- int i = 0;
+ /* We asked to offline set of blocks, but Linux could have lied.
+ * To be safe, check whether blocks were offlined and start again if not
+ */
- for (i = 0; i < num_blocks; i++) {
- FILE * block_file = NULL;
- char fname[256];
+ {
+ int i = 0;
- memset(fname, 0, 256);
+ mem_ready = 1; // Hopefully we are ok...
- snprintf(fname, 256, "%smemory%d/state", SYS_PATH, i + reg_start);
-
- block_file = fopen(fname, "r+");
- if (block_file == NULL) {
- perror("Could not open block file");
- return -1;
- }
+ for (i = 0; i < num_blocks; i++) {
+ int block_fd = NULL;
+ char fname[BUF_SIZE];
+ char status_buf[BUF_SIZE];
+
+ memset(fname, 0, BUF_SIZE);
+ memset(status_buf, 0, BUF_SIZE);
- printf("Offlining block %d (%s)\n", i + reg_start, fname);
- fprintf(block_file, "offline\n");
+ snprintf(fname, BUF_SIZE, "%smemory%d/state", SYS_PATH, i + reg_start);
- fclose(block_file);
+
+ block_fd = open(fname, O_RDONLY);
+
+ if (block_fd == -1) {
+ perror("Could not open block file");
+ return -1;
+ }
+
+ if (read(block_fd, status_buf, BUF_SIZE) <= 0) {
+ perror("Could not read block status");
+ return -1;
+ }
+
+ printf("Checking offlined block %d (%s)...", i + reg_start, fname);
+
+ int ret = strncmp(status_buf, "offline", strlen("offline"));
+
+ if (ret != 0) {
+ int j = 0;
+ int major = (i + reg_start) / 8;
+ int minor = (i + reg_start) % 8;
+
+ bitmap[major] &= ~(0x1 << minor); // mark the block as not removable in bitmap
+
+ mem_ready = 0; // Keep searching
+
+ printf("ERROR (%d)\n", ret);
+
+ for (j = 0; j < i; j++) {
+ FILE * block_file = NULL;
+ char fname[256];
+
+ memset(fname, 0, 256);
+
+ snprintf(fname, 256, "%smemory%d/state", SYS_PATH, j + reg_start);
+
+ block_file = fopen(fname, "r+");
+
+ if (block_file == NULL) {
+ perror("Could not open block file");
+ return -1;
+ }
+
+ fprintf(block_file, "online\n");
+
+ fclose(block_file);
+ }
+
+
+ break;
+ }
+
+ printf("OK\n");
+
+ }
+
+
}
}
+ free(bitmap);
/* Memory is offlined. Calculate size and phys start addr to send to Palacios */
+++ /dev/null
-/*
- * V3 Control utility for Palacios network services
- * (c) Lei Xia, 2010
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <string.h>
-
-#include "v3_ctrl.h"
-
-struct v3_network {
- unsigned char socket;
- unsigned char packet;
- unsigned char vnet;
-};
-
-int main(int argc, char* argv[]) {
- int v3_fd = 0;
- struct v3_network net;
- int i;
-
- if (argc <= 1) {
- printf("Usage: ./v3_mem [socket] [packet] [vnet]\n");
- return -1;
- }
-
- for (i = 1; i < argc; i++){
- if(!strcasecmp (argv[i], "packet")){
- net.packet = 1;
- }else if(!strcasecmp (argv[i], "socket")){
- net.socket = 1;
- }else if(!strcasecmp (argv[i], "vnet")){
- net.vnet = 1;
- }else {
- printf("unknown v3 network service: %s, ignored\n", argv[i]);
- }
- }
-
- printf("Network service: socket: %d, packet: %d, vnet: %d\n", net.socket, net.packet, net.vnet);
-
- v3_fd = open(v3_dev, O_RDONLY);
-
- if (v3_fd == -1) {
- printf("Error opening V3Vee control device\n");
- return -1;
- }
-
- ioctl(v3_fd, V3_START_NETWORK, &net);
-
-
- /* Close the file descriptor. */
- close(v3_fd);
-
-
- return 0;
-}
-
+++ /dev/null
-/*
- * V3 Console utility
- * (c) Jack lange & Lei Xia, 2010
- */
-
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <pthread.h>
-#include <errno.h>
-#include<linux/unistd.h>
-#include <curses.h>
-
-
-#include "v3_ctrl.h"
-
-static int cons_fd = -1;
-static pthread_t input_handler;
-
-void *write_handler(void *val){
- char read;
- printf("Write handler active\n");
- fflush(stdout);
- while(1){
- read = getchar();
- if(write(cons_fd, &read, sizeof(char)) < 0){
- printf("WRITE ERROR");
- }
- }
-}
-
-
-int main(int argc, char* argv[]) {
- int vm_fd;
- fd_set rset;
- char *vm_dev = NULL;
- char *stream;
-
- if (argc < 2) {
- printf("Usage: ./v3_cons vm_device serial_number\n");
- return -1;
- }
-
- vm_dev = argv[1];
- stream = argv[2];
-
- vm_fd = open(vm_dev, O_RDONLY);
- if (vm_fd == -1) {
- printf("Error opening VM device: %s\n", vm_dev);
- return -1;
- }
-
- cons_fd = ioctl(vm_fd, V3_VM_SERIAL_CONNECT, stream);
-
- /* Close the file descriptor. */
- close(vm_fd);
- if (cons_fd < 0) {
- printf("Error opening stream Console\n");
- return -1;
- }
-
-
- if(pthread_create(&input_handler,0,write_handler,0)){
- perror("pthread_create");
- exit(-1);
- }
-
-
- while (1) {
- int ret;
- char cons_buf[1024];
- memset(cons_buf, 0, sizeof(cons_buf));
- int bytes_read = 0;
-
- FD_ZERO(&rset);
- FD_SET(cons_fd, &rset);
-
- ret = select(cons_fd + 1, &rset, NULL, NULL, NULL);
-
- if (ret == 1) {
- bytes_read = read(cons_fd, cons_buf, 1024);
- cons_buf[bytes_read]='\0';
- printf("%s", cons_buf);
- } else {
- printf("v3_cons ERROR: select returned %d\n", ret);
- return -1;
- }
- }
-
-
- return 0;
-}
-
-
--- /dev/null
+/*
+ * V3 Console utility
+ * (c) Jack lange & Lei Xia, 2010
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <errno.h>
+#include<linux/unistd.h>
+#include <curses.h>
+
+
+#include "v3_ctrl.h"
+
+#define BUF_LEN 1025
+#define STREAM_NAME_LEN 128
+
+int main(int argc, char* argv[]) {
+ int vm_fd;
+ fd_set rset;
+ char * vm_dev = NULL;
+ char stream[STREAM_NAME_LEN];
+ char cons_buf[BUF_LEN];
+ int stream_fd = 0;
+
+ if (argc < 2) {
+ printf("Usage: ./v3_cons vm_device serial_number\n");
+ return -1;
+ }
+
+ vm_dev = argv[1];
+
+ if (strlen(argv[2]) >= STREAM_NAME_LEN) {
+ printf("ERROR: Stream name longer than maximum size (%d)\n", STREAM_NAME_LEN);
+ return -1;
+ }
+
+ memcpy(stream, argv[2], strlen(argv[2]));
+
+ vm_fd = open(vm_dev, O_RDONLY);
+ if (vm_fd == -1) {
+ printf("Error opening VM device: %s\n", vm_dev);
+ return -1;
+ }
+
+ stream_fd = ioctl(vm_fd, V3_VM_SERIAL_CONNECT, stream);
+
+ /* Close the file descriptor. */
+ close(vm_fd);
+
+ if (stream_fd < 0) {
+ printf("Error opening stream Console\n");
+ return -1;
+ }
+
+ while (1) {
+ int ret;
+ int bytes_read = 0;
+ char in_buf[512];
+
+ memset(cons_buf, 0, BUF_LEN);
+
+
+ FD_ZERO(&rset);
+ FD_SET(stream_fd, &rset);
+ FD_SET(STDIN_FILENO, &rset);
+
+ ret = select(stream_fd + 1, &rset, NULL, NULL, NULL);
+
+ if (ret == 0) {
+ continue;
+ } else if (ret == -1) {
+ perror("Select returned error\n");
+ return -1;
+ }
+
+ if (FD_ISSET(stream_fd, &rset)) {
+
+ bytes_read = read(stream_fd, cons_buf, BUF_LEN - 1);
+
+ cons_buf[bytes_read]='\0';
+ printf("%s", cons_buf);
+ fflush(stdout);
+
+ } else if (FD_ISSET(STDIN_FILENO, &rset)) {
+ fgets(in_buf, 512, stdin);
+
+ if (write(stream_fd, in_buf, strlen(in_buf)) != strlen(in_buf)) {
+ fprintf(stderr, "Error sending input bufer\n");
+ return -1;
+ }
+ } else {
+ printf("v3_cons ERROR: select returned %d\n", ret);
+ return -1;
+ }
+
+
+ }
+
+
+ return 0;
+}
+
+
#define VIRTIO_NET_SUBDEVICE_ID 1
#define VIRTIO_BLOCK_SUBDEVICE_ID 2
+#define VIRTIO_CONSOLE_SUBDEVICE_ID 3
#define VIRTIO_BALLOON_SUBDEVICE_ID 5
#define VIRTIO_SYMBIOTIC_SUBDEVICE_ID 10
#define VIRTIO_SYMMOD_SUBDEVICE_ID 11
#define VIRTIO_VNET_SUBDEVICE_ID 12
+
#define HOST_FEATURES_PORT 0
#define GUEST_FEATURES_PORT 4
#define VRING_PG_NUM_PORT 8
+struct v3_stream {
+ void * host_stream_data;
+ void * guest_stream_data;
+ uint64_t (*input)(struct v3_stream * stream, uint8_t * buf, uint64_t len);
+};
+
+
#ifdef __V3VEE__
#include <palacios/vmm.h>
-typedef void * v3_stream_t;
+
/* VM Can be NULL */
-v3_stream_t v3_stream_open(struct v3_vm_info * vm, const char * name);
-int v3_stream_write(v3_stream_t stream, uint8_t * buf, uint32_t len);
+struct v3_stream * v3_stream_open(struct v3_vm_info * vm, const char * name,
+ uint64_t (*input)(struct v3_stream * stream, uint8_t * buf, uint64_t len),
+ void * guest_stream_data);
+
+uint64_t v3_stream_output(struct v3_stream * stream, uint8_t * buf, uint32_t len);
-void v3_stream_close(v3_stream_t stream);
+void v3_stream_close(struct v3_stream * stream);
#endif
struct v3_stream_hooks {
- void *(*open)(const char * name, void * private_data);
- int (*write)(void * stream, char * buf, int len);
- void (*close)(void * stream);
+ void *(*open)(struct v3_stream * stream, const char * name, void * host_vm_data);
+ uint64_t (*output)(struct v3_stream * stream, char * buf, int len);
+ void (*close)(struct v3_stream * stream);
};
#include <palacios/vmm_cpuid.h>
#include <palacios/vmm_regs.h>
#include <palacios/vmm_extensions.h>
-
+#include <palacios/vmm_barrier.h>
#ifdef V3_CONFIG_TELEMETRY
v3_vm_operating_mode_t run_state;
-
+ struct v3_barrier barrier;
struct v3_extensions extensions;
if ((os_hooks) && (os_hooks)->start_kernel_thread) { \
(os_hooks)->start_kernel_thread(fn, arg, name); \
} \
- }
+ } while (0)
struct v3_vm_info * v3_create_vm(void * cfg, void * priv_data, char * name);
int v3_start_vm(struct v3_vm_info * vm, unsigned int cpu_mask);
int v3_stop_vm(struct v3_vm_info * vm);
+int v3_pause_vm(struct v3_vm_info * vm);
+int v3_continue_vm(struct v3_vm_info * vm);
+
+
int v3_free_vm(struct v3_vm_info * vm);
int v3_deliver_irq(struct v3_vm_info * vm, struct v3_interrupt * intr);
#ifdef __V3VEE__
+#include <palacios/vmm_lock.h>
+#include <palacios/vmm_bitmap.h>
+
-#include <util/vmm_lock.h>
struct v3_barrier {
- uint64_t cpus;
int active; // If 1, barrier is active, everyone must wait
// If 0, barrier is clear, can proceed
+ struct v3_bitmap cpu_map;
+
v3_lock_t lock;
};
+struct v3_vm_info;
+struct guest_info;
+
+int v3_init_barrier(struct v3_vm_info * vm_info);
+int v3_deinit_barrier(struct v3_vm_info * vm_info);
-int v3_init_barrier(struct v3_barrier * barrier);
+int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core);
+int v3_lower_barrier(struct v3_vm_info * vm_info);
-int v3_activate_barrier(struct guest_info * core);
-int v3_check_barrier(struct guest_info * core);
+int v3_wait_at_barrier(struct guest_info * core);
#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) 2011, Jack Lange <jacklange@cs.pitt.edu>
+ * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jacklange@cs.pitt.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+
+
+#ifndef __VMM_BITMAP_H__
+#define __VMM_BITMAP_H__
+
+#ifdef __V3VEE__
+#include <palacios/vmm_types.h>
+
+
+
+struct v3_bitmap {
+ int num_bits; // number of valid bit positions in the bitmap
+ uint8_t * bits; // actual bitmap. Dynamically allocated... ugly
+};
+
+
+int v3_bitmap_init(struct v3_bitmap * bitmap, int num_bits);
+void v3_bitmap_deinit(struct v3_bitmap * bitmap);
+int v3_bitmap_reset(struct v3_bitmap * bitmap);
+
+int v3_bitmap_set(struct v3_bitmap * bitmap, int index);
+int v3_bitmap_clear(struct v3_bitmap * bitmap, int index);
+int v3_bitmap_check(struct v3_bitmap * bitmap, int index);
+
+
+
+#endif
+
+#endif
uint32_t val;
struct {
- uint_t lock : 1; // 0xF0
- uint_t repne : 1; // 0xF2
- uint_t repnz : 1; // 0xF2
- uint_t rep : 1; // 0xF3
- uint_t repe : 1; // 0xF3
- uint_t repz : 1; // 0xF3
- uint_t cs_override : 1; // 0x2E
- uint_t ss_override : 1; // 0x36
- uint_t ds_override : 1; // 0x3E
- uint_t es_override : 1; // 0x26
- uint_t fs_override : 1; // 0x64
- uint_t gs_override : 1; // 0x65
- uint_t br_not_taken : 1; // 0x2E
- uint_t br_taken : 1; // 0x3E
- uint_t op_size : 1; // 0x66
- uint_t addr_size : 1; // 0x67
-
- uint_t rex : 1;
+ uint32_t lock : 1; // 0xF0
+ uint32_t repne : 1; // 0xF2
+ uint32_t repnz : 1; // 0xF2
+ uint32_t rep : 1; // 0xF3
+ uint32_t repe : 1; // 0xF3
+ uint32_t repz : 1; // 0xF3
+ uint32_t cs_override : 1; // 0x2E
+ uint32_t ss_override : 1; // 0x36
+ uint32_t ds_override : 1; // 0x3E
+ uint32_t es_override : 1; // 0x26
+ uint32_t fs_override : 1; // 0x64
+ uint32_t gs_override : 1; // 0x65
+ uint32_t br_not_taken : 1; // 0x2E
+ uint32_t br_taken : 1; // 0x3E
+ uint32_t op_size : 1; // 0x66
+ uint32_t addr_size : 1; // 0x67
+
+ uint32_t rex : 1;
- uint_t rex_rm : 1; // REX.B
- uint_t rex_sib_idx : 1; // REX.X
- uint_t rex_reg : 1; // REX.R
- uint_t rex_op_size : 1; // REX.W
+ uint32_t rex_rm : 1; // REX.B
+ uint32_t rex_sib_idx : 1; // REX.X
+ uint32_t rex_reg : 1; // REX.R
+ uint32_t rex_op_size : 1; // REX.W
+
+ uint32_t rsvd : 11;
} __attribute__((packed));
} __attribute__((packed));
} __attribute__((packed));
int (*write)(uint8_t * buf, uint64_t lba, uint64_t num_bytes, void * private_data);
};
+
+struct v3_dev_net_ops_cfg{
+ void * frontend_data;
+ char * fnt_mac;
+ int quote;
+ int poll; /* need poll? */
+};
+
struct v3_dev_net_ops {
/* Backend implemented functions */
- int (*send)(uint8_t * buf, uint32_t len, int synchronize, void * private_data);
+ int (*send)(uint8_t * buf, uint32_t len, void * private_data);
/* Frontend implemented functions */
int (*recv)(uint8_t * buf, uint32_t len, void * frnt_data);
+ int (*poll)(int quote, void * frnt_data);
/* This is ugly... */
- void * frontend_data;
- char fnt_mac[ETH_ALEN];
+ struct v3_dev_net_ops_cfg config;
};
struct v3_dev_console_ops {
struct v3_dev_char_ops {
/* Backend implemented functions */
- int (*write)(uint8_t * buf, uint64_t len, void * private_data);
+ uint64_t (*output)(uint8_t * buf, uint64_t len, void * private_data);
// int (*read)(uint8_t * buf, uint64_t len, void * private_data);
/* Frontend Implemented functions */
- int (*push)(struct v3_vm_info * vm, uint8_t * buf, uint64_t len, void * private_data);
+ uint64_t (*input)(struct v3_vm_info * vm, uint8_t * buf, uint64_t len, void * private_data);
};
#include <palacios/vmm_types.h>
+#define FLAGS_MASK 0x00000cff
+
#define MAKE_1OP_8FLAGS_INST(iname) static inline void iname##8(addr_t * dst, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint8_t tmp_dst = *(uint8_t *)dst; \
\
asm volatile ( \
"pushf; " \
"pushf; " \
"pop %1; " \
"popf; " \
- : "=q"(*(uint8_t *)dst),"=q"(*flags) \
- : "q"(*flags), "0"(*(uint8_t *)dst) \
+ : "=&q"(tmp_dst),"=q"(guest_flags) \
+ : "1"(guest_flags), "0"(tmp_dst) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
+ *(uint8_t *)dst = tmp_dst; \
\
}
#define MAKE_1OP_16FLAGS_INST(iname) static inline void iname##16(addr_t * dst, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint16_t tmp_dst = *(uint16_t *)dst; \
\
asm volatile ( \
"pushf; " \
"pushf; " \
"pop %1; " \
"popf; " \
- : "=q"(*(uint16_t *)dst),"=q"(*flags) \
- : "q"(*flags), "0"(*(uint16_t *)dst) \
+ : "=&q"(tmp_dst),"=q"(guest_flags) \
+ : "1"(guest_flags), "0"(tmp_dst) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
- \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
+ *(uint16_t *)dst = tmp_dst; \
}
#define MAKE_1OP_32FLAGS_INST(iname) static inline void iname##32(addr_t * dst, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint32_t tmp_dst = *(uint32_t *)dst; \
\
asm volatile ( \
"pushf; " \
"pushf; " \
"pop %1; " \
"popf; " \
- : "=q"(*(uint32_t *)dst),"=q"(*flags) \
- : "q"(*flags), "0"(*(uint32_t *)dst) \
+ : "=&q"(tmp_dst),"=q"(guest_flags) \
+ : "1"(guest_flags), "0"(tmp_dst) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
\
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
+ *(uint32_t *)dst = tmp_dst; \
}
#define MAKE_1OP_64FLAGS_INST(iname) static inline void iname##64(addr_t * dst, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint64_t tmp_dst = *(uint64_t *)dst; \
\
asm volatile ( \
"pushfq; " \
"pushfq; " \
"pop %1; " \
"popfq; " \
- : "=q"(*(uint64_t *)dst),"=q"(*flags) \
- : "q"(*flags), "0"(*(uint64_t *)dst) \
+ : "=q"(tmp_dst),"=q"(guest_flags) \
+ : "q"(guest_flags), "0"(tmp_dst) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
\
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
+ *(uint64_t *)dst = tmp_dst; \
}
#define MAKE_1OP_8_INST(iname) static inline void iname##8(addr_t * dst) { \
+ uint8_t tmp_dst = *(uint8_t *)dst; \
asm volatile ( \
#iname"b %0; " \
- : "=q"(*(uint8_t *)dst) \
- : "0"(*(uint8_t *)dst) \
+ : "=q"(tmp_dst) \
+ : "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint8_t *)dst = tmp_dst; \
}
#define MAKE_1OP_16_INST(iname) static inline void iname##16(addr_t * dst) { \
+ uint16_t tmp_dst = *(uint16_t *)dst; \
asm volatile ( \
#iname"w %0; " \
- : "=q"(*(uint16_t *)dst) \
- : "0"(*(uint16_t *)dst) \
+ : "=q"(tmp_dst) \
+ : "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint16_t *)dst = tmp_dst; \
}
#define MAKE_1OP_32_INST(iname) static inline void iname##32(addr_t * dst) { \
+ uint32_t tmp_dst = *(uint32_t *)dst; \
asm volatile ( \
#iname"l %0; " \
- : "=q"(*(uint32_t *)dst) \
- : "0"(*(uint32_t *)dst) \
+ : "=q"(tmp_dst) \
+ : "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint32_t *)dst = tmp_dst; \
}
#define MAKE_1OP_64_INST(iname) static inline void iname##64(addr_t * dst) { \
+ uint64_t tmp_dst = *(uint64_t *)dst; \
asm volatile ( \
#iname"q %0; " \
- : "=q"(*(uint64_t *)dst) \
- : "0"(*(uint64_t *)dst) \
+ : "=q"(tmp_dst) \
+ : "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint64_t *)dst = tmp_dst; \
}
#define MAKE_2OP_64FLAGS_INST(iname) static inline void iname##64(addr_t * dst, addr_t * src, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint64_t tmp_dst = *(uint64_t *)dst; \
\
asm volatile ( \
"pushfq\r\n" \
"pushfq\r\n" \
"pop %1\r\n" \
"popfq\r\n" \
- : "=q"(*(uint64_t *)dst),"=q"(*flags) \
- : "q"(*(uint64_t *)src),"q"(*flags), "0"(*(uint64_t *)dst) \
+ : "=&q"(tmp_dst),"=q"(guest_flags) \
+ : "q"(*(uint64_t *)src),"1"(guest_flags), "0"(tmp_dst) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
- \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
+ *(uint64_t *)dst = tmp_dst; \
}
#define MAKE_2OP_32FLAGS_INST(iname) static inline void iname##32(addr_t * dst, addr_t * src, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint32_t tmp_dst = *(uint32_t *)dst; \
\
asm volatile ( \
"pushf; " \
"pushf; " \
"pop %1; " \
"popf; " \
- : "=q"(*(uint32_t *)dst),"=q"(*flags) \
- : "q"(*(uint32_t *)src),"q"(*flags), "0"(*(uint32_t *)dst) \
+ : "=&q"(tmp_dst),"=q"(guest_flags) \
+ : "q"(*(uint32_t *)src),"1"(guest_flags), "0"(tmp_dst) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
+ *(uint32_t *)dst = tmp_dst; \
}
#define MAKE_2OP_16FLAGS_INST(iname) static inline void iname##16(addr_t * dst, addr_t * src, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint16_t tmp_dst = *(uint16_t *)dst; \
\
asm volatile ( \
"pushf; " \
"pushf; " \
"pop %1; " \
"popf; " \
- : "=q"(*(uint16_t *)dst),"=q"(*flags) \
- : "q"(*(uint16_t *)src),"q"(*flags), "0"(*(uint16_t *)dst) \
+ : "=&q"(tmp_dst),"=q"(guest_flags) \
+ : "q"(*(uint16_t *)src),"1"(guest_flags), "0"(tmp_dst) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
+ *(uint16_t *)dst = tmp_dst; \
}
#define MAKE_2OP_8FLAGS_INST(iname) static inline void iname##8(addr_t * dst, addr_t * src, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint8_t tmp_dst = *(uint8_t *)dst; \
\
asm volatile ( \
"pushf; " \
"pushf; " \
"pop %1; " \
"popf; " \
- : "=q"(*(uint8_t *)dst),"=q"(*flags) \
- : "q"(*(uint8_t *)src),"q"(*flags), "0"(*(uint8_t *)dst) \
+ : "=q"(tmp_dst),"=q"(guest_flags) \
+ : "q"(*(uint8_t *)src),"1"(guest_flags), "0"(tmp_dst) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
+ *(uint8_t *)dst = tmp_dst; \
}
#define MAKE_2OP_64STR_INST(iname) static inline void iname##64(addr_t * dst, \
addr_t * src, \
addr_t * ecx, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint64_t tmp_dst = 0, tmp_ecx = 0, tmp_src = 0; \
\
asm volatile ( \
"pushfq; " \
- "pushq %4; " \
+ "pushq %7; " \
"popfq; " \
"rep; " \
#iname"q; " \
"pushfq; " \
"popq %0; " \
"popfq; " \
- : "=q"(*flags) \
- : "D"(*dst),"S"(*src),"c"(*ecx),"q"(*flags) \
+ : "=q"(guest_flags), "=&D"(tmp_dst), "=&S"(tmp_src), "=&c"(tmp_ecx) \
+ : "1"(*dst),"2"(*src),"3"(*ecx),"0"(guest_flags) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
}
#define MAKE_2OP_32STR_INST(iname) static inline void iname##32(addr_t * dst, \
addr_t * src, \
addr_t * ecx, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint32_t tmp_dst = 0, tmp_ecx = 0, tmp_src = 0; \
\
asm volatile ( \
"pushf; " \
- "push %4; " \
+ "push %7; " \
"popf; " \
"rep; " \
#iname"l; " \
"pushf; " \
"pop %0; " \
"popf; " \
- : "=q"(*flags) \
- : "D"(*dst),"S"(*src),"c"(*ecx),"q"(*flags) \
+ : "=q"(guest_flags), "=&D"(tmp_dst), "=&S"(tmp_src), "=&c"(tmp_ecx) \
+ : "1"(*dst),"2"(*src),"3"(*ecx),"0"(guest_flags) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
}
#define MAKE_2OP_16STR_INST(iname) static inline void iname##16(addr_t * dst, \
addr_t * src, \
addr_t * ecx, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint16_t tmp_dst = 0, tmp_ecx = 0, tmp_src = 0; \
\
asm volatile ( \
"pushf; " \
- "push %4; " \
+ "push %7; " \
"popf; " \
"rep; " \
#iname"w; " \
"pushf; " \
"pop %0; " \
"popf; " \
- : "=q"(*flags) \
- : "D"(*dst),"S"(*src),"c"(*ecx),"q"(*flags) \
+ : "=q"(guest_flags), "=&D"(tmp_dst), "=&S"(tmp_src), "=&c"(tmp_ecx) \
+ : "1"(*dst),"2"(*src),"3"(*ecx),"0"(guest_flags) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
}
#define MAKE_2OP_8STR_INST(iname) static inline void iname##8(addr_t * dst, \
addr_t * src, \
addr_t * ecx, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint8_t tmp_dst = 0, tmp_ecx = 0, tmp_src = 0; \
\
asm volatile ( \
"pushf; " \
- "push %4; " \
+ "push %7; " \
"popf; " \
"rep; " \
#iname"b; " \
"pushf; " \
"pop %0; " \
"popf; " \
- : "=q"(*flags) \
- : "D"(*dst),"S"(*src),"c"(*ecx),"q"(*flags) \
+ : "=q"(guest_flags), "=&D"(tmp_dst), "=&S"(tmp_src), "=&c"(tmp_ecx) \
+ : "1"(*dst),"2"(*src),"3"(*ecx),"0"(guest_flags) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
}
#define MAKE_1OP_64STR_INST(iname) static inline void iname##64(addr_t * dst, \
addr_t * src, \
addr_t * ecx, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint64_t tmp_dst = 0, tmp_ecx = 0; \
\
asm volatile ( \
"pushfq; " \
- "pushq %4; " \
+ "pushq %6; " \
"popfq; " \
"rep; " \
#iname"q; " \
"pushfq; " \
"popq %0; " \
"popfq; " \
- : "=q"(*flags) \
- : "D"(*dst),"a"(*src),"c"(*ecx),"q"(*flags) \
+ : "=&q"(guest_flags), "=&D"(tmp_dst), "=&c"(tmp_ecx) \
+ : "1"(*dst),"a"(*src),"2"(*ecx),"0"(guest_flags) \
+ : "memory" \
); \
\
- *flags |= flags_rsvd; \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
}
#define MAKE_1OP_32STR_INST(iname) static inline void iname##32(addr_t * dst, \
addr_t * src, \
addr_t * ecx, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint32_t tmp_dst = 0, tmp_ecx = 0; \
\
asm volatile ( \
"pushf; " \
- "push %4; " \
+ "push %6; " \
"popf; " \
"rep; " \
#iname"l; " \
"pushf; " \
"pop %0; " \
"popf; " \
- : "=q"(*flags) \
- : "D"(*dst),"a"(*src),"c"(*ecx),"q"(*flags) \
+ : "=&q"(guest_flags), "=&D"(tmp_dst), "=&c"(tmp_ecx) \
+ : "1"(*dst),"a"(*src),"2"(*ecx),"0"(guest_flags) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
+ \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
}
#define MAKE_1OP_16STR_INST(iname) static inline void iname##16(addr_t * dst, \
addr_t * src, \
addr_t * ecx, addr_t * flags) { \
- /* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & FLAGS_MASK; \
+ uint16_t tmp_dst = 0, tmp_ecx = 0; \
\
asm volatile ( \
"pushf; " \
- "push %4; " \
+ "push %6; " \
"popf; " \
"rep; " \
#iname"w; " \
"pushf; " \
"pop %0; " \
"popf; " \
- : "=q"(*flags) \
- : "D"(*dst),"a"(*src),"c"(*ecx),"q"(*flags) \
+ : "=q"(guest_flags), "=&D"(tmp_dst), "=&c"(tmp_ecx) \
+ : "1"(*dst),"a"(*src),"2"(*ecx),"0"(guest_flags) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
}
addr_t * src, \
addr_t * ecx, addr_t * flags) { \
/* Some of the flags values are not copied out in a pushf, we save them here */ \
- addr_t flags_rsvd = *flags & ~0xfffc7fff; \
+ addr_t guest_flags = *flags & 0x00000cff; \
+ uint8_t tmp_dst = 0, tmp_ecx = 0; \
\
asm volatile ( \
"pushf; " \
- "push %4; " \
+ "push %6; " \
"popf; " \
"rep; " \
#iname"b; " \
"pushf; " \
"pop %0; " \
"popf; " \
- : "=q"(*flags) \
- : "D"(*dst),"a"(*src),"c"(*ecx),"q"(*flags) \
+ : "=&q"(guest_flags), "=&D"(tmp_dst), "=&c"(tmp_ecx) \
+ : "1"(*dst),"a"(*src),"2"(*ecx),"0"(guest_flags) \
+ : "memory" \
); \
- *flags |= flags_rsvd; \
+ *flags &= ~FLAGS_MASK; \
+ *flags |= (guest_flags & FLAGS_MASK); \
}
#define MAKE_2OP_64_INST(iname) static inline void iname##64(addr_t * dst, addr_t * src) { \
+ uint64_t tmp_dst = *(uint64_t *)dst; \
asm volatile ( \
#iname"q %1, %0; " \
- : "=q"(*(uint64_t *)dst) \
- : "q"(*(uint64_t *)src), "0"(*(uint64_t *)dst) \
+ : "=&q"(tmp_dst) \
+ : "q"(*(uint64_t *)src), "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint64_t *)dst = tmp_dst; \
}
#define MAKE_2OP_32_INST(iname) static inline void iname##32(addr_t * dst, addr_t * src) { \
+ uint32_t tmp_dst = *(uint32_t *)dst; \
asm volatile ( \
#iname"l %1, %0; " \
- : "=q"(*(uint32_t *)dst) \
- : "q"(*(uint32_t *)src), "0"(*(uint32_t *)dst) \
+ : "=&q"(tmp_dst) \
+ : "q"(*(uint32_t *)src), "0"(tmp_dst) \
+ : "memory" \
); \
- }
+ *(uint32_t *)dst = tmp_dst; \
+ }
#define MAKE_2OP_16_INST(iname) static inline void iname##16(addr_t * dst, addr_t * src) { \
+ uint16_t tmp_dst = *(uint16_t *)dst; \
asm volatile ( \
#iname"w %1, %0; " \
- : "=q"(*(uint16_t *)dst) \
- : "q"(*(uint16_t *)src), "0"(*(uint16_t *)dst) \
+ : "=&q"(tmp_dst) \
+ : "q"(*(uint16_t *)src), "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint16_t *)dst = tmp_dst; \
}
#define MAKE_2OP_8_INST(iname) static inline void iname##8(addr_t * dst, addr_t * src) { \
+ uint8_t tmp_dst = *(uint8_t *)dst; \
asm volatile ( \
#iname"b %1, %0; " \
- : "=q"(*(uint8_t *)dst) \
- : "q"(*(uint8_t *)src), "0"(*(uint8_t *)dst) \
+ : "=&q"(tmp_dst) \
+ : "q"(*(uint8_t *)src), "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint8_t *)dst = tmp_dst; \
}
#define MAKE_2OP_8EXT_INST(iname) static inline void iname##8(addr_t * dst, addr_t * src, uint_t dst_len) { \
if (dst_len == 2) { \
+ uint16_t tmp_dst = *(uint16_t *)dst; \
asm volatile ( \
#iname" %1, %0; " \
- : "=q"(*(uint16_t *)dst) \
- : "q"(*(uint8_t *)src), "0"(*(uint16_t *)dst) \
+ : "=&q"(tmp_dst) \
+ : "q"(*(uint8_t *)src), "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint16_t *)dst = tmp_dst; \
} else if (dst_len == 4) { \
+ uint32_t tmp_dst = *(uint32_t *)dst; \
asm volatile ( \
#iname" %1, %0; " \
- : "=q"(*(uint32_t *)dst) \
- : "q"(*(uint8_t *)src), "0"(*(uint32_t *)dst) \
+ : "=&q"(tmp_dst) \
+ : "q"(*(uint8_t *)src), "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint32_t *)dst = tmp_dst; \
} else if (dst_len == 8) { \
+ uint64_t tmp_dst = *(uint64_t *)dst; \
asm volatile ( \
#iname" %1, %0; " \
- : "=q"(*(uint64_t *)dst) \
- : "q"(*(uint8_t *)src), "0"(*(uint64_t *)dst) \
+ : "=&q"(tmp_dst) \
+ : "q"(*(uint8_t *)src), "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint64_t *)dst = tmp_dst; \
} \
}
#define MAKE_2OP_16EXT_INST(iname) static inline void iname##16(addr_t * dst, addr_t * src, uint_t dst_len) { \
if (dst_len == 4) { \
+ uint32_t tmp_dst = *(uint32_t *)dst; \
asm volatile ( \
#iname" %1, %0; " \
- : "=q"(*(uint32_t *)dst) \
- : "q"(*(uint16_t *)src), "0"(*(uint32_t *)dst) \
+ : "=&q"(tmp_dst) \
+ : "q"(*(uint16_t *)src), "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint32_t *)dst = tmp_dst; \
} else if (dst_len == 8) { \
+ uint64_t tmp_dst = *(uint64_t *)dst; \
asm volatile ( \
#iname" %1, %0; " \
- : "=q"(*(uint64_t *)dst) \
- : "q"(*(uint16_t *)src), "0"(*(uint64_t *)dst) \
+ : "=&q"(tmp_dst) \
+ : "q"(*(uint16_t *)src), "0"(tmp_dst) \
+ : "memory" \
); \
+ *(uint64_t *)dst = tmp_dst; \
} \
}
#define MAKE_2OUT_64_INST(iname) static inline void iname##64(addr_t * dst, addr_t * src) { \
+ uint64_t tmp_dst = *(uint64_t *)dst; \
+ uint64_t tmp_src = *(uint64_t *)src; \
+ \
asm volatile ( \
#iname"q %1, %0; " \
- : "=q"(*(uint64_t *)dst), "=q"(*(uint64_t *)src) \
- : "0"(*(uint64_t *)dst), "1"(*(uint64_t *)src) \
+ : "=&q"(tmp_dst), "=&q"(tmp_src) \
+ : "0"(tmp_dst), "1"(tmp_src) \
+ : "memory" \
); \
+ *(uint64_t *)src = tmp_src; \
+ *(uint64_t *)dst = tmp_dst; \
}
#define MAKE_2OUT_32_INST(iname) static inline void iname##32(addr_t * dst, addr_t * src) { \
+ uint32_t tmp_dst = *(uint32_t *)dst; \
+ uint32_t tmp_src = *(uint32_t *)src; \
+ \
asm volatile ( \
#iname"l %1, %0; " \
- : "=q"(*(uint32_t *)dst), "=q"(*(uint32_t *)src) \
- : "0"(*(uint32_t *)dst), "1"(*(uint32_t *)src) \
+ : "=&q"(tmp_dst), "=&q"(tmp_src) \
+ : "0"(tmp_dst), "1"(tmp_src) \
+ : "memory" \
); \
+ *(uint32_t *)src = tmp_src; \
+ *(uint32_t *)dst = tmp_dst; \
}
#define MAKE_2OUT_16_INST(iname) static inline void iname##16(addr_t * dst, addr_t * src) { \
+ uint16_t tmp_dst = *(uint16_t *)dst; \
+ uint16_t tmp_src = *(uint16_t *)src; \
+ \
asm volatile ( \
#iname"w %1, %0; " \
- : "=q"(*(uint16_t *)dst), "=q"(*(uint16_t *)src) \
- : "0"(*(uint16_t *)dst), "1"(*(uint16_t *)src) \
+ : "=&q"(tmp_dst), "=&q"(tmp_src) \
+ : "0"(tmp_dst), "1"(tmp_src) \
+ : "memory" \
); \
+ *(uint16_t *)src = tmp_src; \
+ *(uint16_t *)dst = tmp_dst; \
}
#define MAKE_2OUT_8_INST(iname) static inline void iname##8(addr_t * dst, addr_t * src) { \
+ uint8_t tmp_dst = *(uint8_t *)dst; \
+ uint8_t tmp_src = *(uint8_t *)src; \
+ \
asm volatile ( \
#iname"b %1, %0; " \
- : "=q"(*(uint8_t *)dst), "=q"(*(uint8_t *)src) \
- : "0"(*(uint8_t *)dst), "1"(*(uint8_t *)src) \
+ : "=&q"(tmp_dst), "=&q"(tmp_src) \
+ : "0"(tmp_dst), "1"(tmp_src) \
+ : "memory" \
); \
+ *(uint8_t *)src = tmp_src; \
+ *(uint8_t *)dst = tmp_dst; \
}
+++ /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) 2011, Jack Lange <jarusl@cs.northwestern.edu>
- * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
- * All rights reserved.
- *
- * Author: Jack Lange <jarusl@cs.northwestern.edu>
- *
- * This is free software. You are permitted to use,
- * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
- */
-
-#ifndef __VMM_MTRR_H__
-#define __VMM_MTRR_H__
-
-
-#ifdef __V3VEE__
-
-#include <palacios/vmm.h>
-
-
-
-#endif
-
-#endif
typedef enum {SHADOW_PAGING, NESTED_PAGING} v3_paging_mode_t;
-typedef enum {VM_RUNNING, VM_STOPPED, VM_SUSPENDED, VM_ERROR, VM_EMULATING} v3_vm_operating_mode_t;
+typedef enum {VM_RUNNING, VM_STOPPED, VM_PAUSED, VM_ERROR} v3_vm_operating_mode_t;
typedef enum {CORE_RUNNING, CORE_STOPPED} v3_core_operating_mode_t;
typedef enum {REAL, /*UNREAL,*/ PROTECTED, PROTECTED_PAE, LONG, LONG_32_COMPAT, LONG_16_COMPAT} v3_cpu_mode_t;
int v3_vnet_add_route(struct v3_vnet_route route);
void v3_vnet_del_route(uint32_t route_idx);
-int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data, int synchronize);
+int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data);
int v3_vnet_find_dev(uint8_t * mac);
int v3_vnet_stat(struct vnet_stat * stats);
int (*input)(struct v3_vm_info * vm,
struct v3_vnet_pkt * pkt,
void * dev_data);
+
+ /* return >0 means there are more pkts in the queue to be sent */
+ int (*poll)(struct v3_vm_info * vm,
+ int quote,
+ void * dev_data);
};
int v3_init_vnet(void);
void v3_deinit_vnet(void);
int v3_vnet_add_dev(struct v3_vm_info * info, uint8_t * mac,
- struct v3_vnet_dev_ops * ops,
+ struct v3_vnet_dev_ops * ops, int quote, int poll_state,
void * priv_data);
int v3_vnet_del_dev(int dev_id);
help
Enable debugging for the Linux Virtio Symbiotic Device
+config LINUX_VIRTIO_CONSOLE
+ bool "Enable Virtio Console Device"
+ default n
+ depends on PCI
+ help
+ Enable the Virtio Console
+
+
config LINUX_VIRTIO_NET
bool "Enable Virtio Network Device"
default n
help
Include virtual serial port
+config DEBUG_SERIAL
+ bool "Debug Serial Port"
+ default n
+ depends on SERIAL_UART
+ help
+ Debugging virtual serial port
+
config CHAR_STREAM
bool "Stream based character frontend"
depends on STREAM
obj-$(V3_CONFIG_LINUX_VIRTIO_SYM) += lnx_virtio_sym.o
obj-$(V3_CONFIG_LINUX_VIRTIO_NET) += lnx_virtio_nic.o
obj-$(V3_CONFIG_LINUX_VIRTIO_VNET) += lnx_virtio_vnet.o
+obj-$(V3_CONFIG_LINUX_VIRTIO_CONSOLE) += lnx_virtio_console.o
obj-$(V3_CONFIG_VNET_NIC) += vnet_nic.o
obj-$(V3_CONFIG_NVRAM) += nvram.o
obj-$(V3_CONFIG_OS_DEBUG) += os_debug.o
PrintDebug("Enabling CGA Passthrough\n");
if (v3_hook_write_mem(vm, V3_MEM_CORE_ANY, START_ADDR, END_ADDR,
START_ADDR, &video_write_mem, dev) == -1) {
- PrintDebug("\n\nVideo Hook failed.\n\n");
+ PrintError("\n\nVideo Hook failed.\n\n");
+ return -1;
}
} else {
if (v3_hook_write_mem(vm, V3_MEM_CORE_ANY, START_ADDR, END_ADDR,
video_state->framebuf_pa, &video_write_mem, dev) == -1) {
- PrintDebug("\n\nVideo Hook failed.\n\n");
+ PrintError("\n\nVideo Hook failed.\n\n");
+ return -1;
}
}
struct stream_state {
- v3_stream_t stream;
+ struct v3_stream * stream;
struct v3_dev_char_ops char_ops;
+ struct v3_vm_info * vm;
+
void * push_fn_arg;
};
-static int serial_event_handler(struct v3_vm_info * vm,
- struct v3_serial_event * evt,
- void * private_data) {
- struct stream_state * state = (struct stream_state *)private_data;
+static uint64_t stream_input(struct v3_stream * stream, uint8_t * buf, uint64_t len) {
+ struct stream_state * state = stream->guest_stream_data;
- if (state->char_ops.push != NULL){
- state->char_ops.push(vm, evt->data, evt->len, state->push_fn_arg);
- }
+ return state->char_ops.input(state->vm, buf, len, state->push_fn_arg);
- return 0;
}
-static int stream_write(uint8_t * buf, uint64_t length, void * private_data) {
+static uint64_t stream_output(uint8_t * buf, uint64_t length, void * private_data) {
struct stream_state * state = (struct stream_state *)private_data;
-
- return v3_stream_write(state->stream, buf, length);
+
+ return v3_stream_output(state->stream, buf, length);
}
static int stream_free(struct stream_state * state) {
}
-
- state->stream = v3_stream_open(vm, stream_name);
+ state->stream = v3_stream_open(vm, stream_name, stream_input, state);
if (state->stream == NULL) {
PrintError("Could not open stream %s\n", stream_name);
return -1;
}
- state->char_ops.write = stream_write;
+ state->vm = vm;
+ state->char_ops.output = stream_output;
if (v3_dev_connect_char(vm, v3_cfg_val(frontend_cfg, "tag"),
&(state->char_ops), frontend_cfg,
return -1;
}
- v3_hook_host_event(vm, HOST_SERIAL_EVT, V3_HOST_EVENT_HANDLER(serial_event_handler), state);
+
return 0;
}
--- /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) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm.h>
+#include <palacios/vmm_dev_mgr.h>
+#include <devices/lnx_virtio_pci.h>
+#include <palacios/vm_guest_mem.h>
+
+#include <devices/pci.h>
+
+
+
+struct console_config {
+ uint16_t cols;
+ uint16_t rows;
+} __attribute__((packed));
+
+
+
+
+#define QUEUE_SIZE 128
+
+/* Host Feature flags */
+#define VIRTIO_CONSOLE_F_SIZE 0x1
+
+struct virtio_console_state {
+ struct console_config cons_cfg;
+ struct virtio_config virtio_cfg;
+
+ struct vm_device * pci_bus;
+ struct pci_device * pci_dev;
+
+ struct virtio_queue queue[2];
+
+ struct v3_stream * stream;
+
+
+ struct virtio_queue * cur_queue;
+
+ struct v3_vm_info * vm;
+
+ int io_range_size;
+
+ void * backend_data;
+ struct v3_dev_char_ops * ops;
+};
+
+
+struct virtio_console_state * cons_state = NULL;
+
+static int virtio_reset(struct virtio_console_state * virtio) {
+
+ memset(virtio->queue, 0, sizeof(struct virtio_queue) * 2);
+
+ virtio->cur_queue = &(virtio->queue[0]);
+
+ virtio->virtio_cfg.status = 0;
+ virtio->virtio_cfg.pci_isr = 0;
+
+ /* Console configuration */
+ // virtio->virtio_cfg.host_features = VIRTIO_NOTIFY_HOST;
+
+ // Virtio Console uses two queues
+ virtio->queue[0].queue_size = QUEUE_SIZE;
+ virtio->queue[1].queue_size = QUEUE_SIZE;
+
+
+ memset(&(virtio->cons_cfg), 0, sizeof(struct console_config));
+
+ return 0;
+}
+
+static int get_desc_count(struct virtio_queue * q, int index) {
+ struct vring_desc * tmp_desc = &(q->desc[index]);
+ int cnt = 1;
+
+ while (tmp_desc->flags & VIRTIO_NEXT_FLAG) {
+ tmp_desc = &(q->desc[tmp_desc->next]);
+ cnt++;
+ }
+
+ return cnt;
+}
+
+
+static int handle_kick(struct guest_info * core, struct virtio_console_state * virtio) {
+ struct virtio_queue * q = virtio->cur_queue;
+
+ PrintDebug("VIRTIO CONSOLE KICK: cur_index=%d (mod=%d), avail_index=%d\n",
+ q->cur_avail_idx, q->cur_avail_idx % QUEUE_SIZE, q->avail->index);
+
+ while (q->cur_avail_idx < q->avail->index) {
+ struct vring_desc * tmp_desc = NULL;
+ uint16_t desc_idx = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE];
+ int desc_cnt = get_desc_count(q, desc_idx);
+ int i = 0;
+ uint32_t req_len = 0;
+
+
+ PrintDebug("Descriptor Count=%d, index=%d\n", desc_cnt, q->cur_avail_idx % QUEUE_SIZE);
+
+ for (i = 0; i < desc_cnt; i++) {
+ addr_t page_addr;
+ tmp_desc = &(q->desc[desc_idx]);
+
+
+ PrintDebug("Console output (ptr=%p) gpa=%p, len=%d, flags=%x, next=%d\n",
+ tmp_desc,
+ (void *)(addr_t)(tmp_desc->addr_gpa), tmp_desc->length,
+ tmp_desc->flags, tmp_desc->next);
+
+ if (v3_gpa_to_hva(core, tmp_desc->addr_gpa, (addr_t *)&(page_addr)) == -1) {
+ PrintError("Could not translate block header address\n");
+ return -1;
+ }
+
+ virtio->ops->output((uint8_t *)page_addr, tmp_desc->length, virtio->backend_data);
+
+ PrintDebug("Guest Console Currently Ignored\n");
+
+ req_len += tmp_desc->length;
+ desc_idx = tmp_desc->next;
+ }
+
+ q->used->ring[q->used->index % QUEUE_SIZE].id = q->avail->ring[q->cur_avail_idx % QUEUE_SIZE];
+ q->used->ring[q->used->index % QUEUE_SIZE].length = req_len; // What do we set this to????
+
+ q->used->index++;
+ q->cur_avail_idx++;
+ }
+
+ if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
+ PrintDebug("Raising IRQ %d\n", virtio->pci_dev->config_header.intr_line);
+ v3_pci_raise_irq(virtio->pci_bus, 0, virtio->pci_dev);
+ virtio->virtio_cfg.pci_isr = VIRTIO_ISR_ACTIVE;
+ }
+
+ return 0;
+}
+
+
+static uint64_t virtio_input(struct v3_vm_info * vm, uint8_t * buf, uint64_t len, void * private_data) {
+ struct virtio_console_state * cons_state = private_data;
+ struct virtio_queue * q = &(cons_state->queue[0]);
+ int xfer_len = 0;
+
+ PrintDebug("VIRTIO CONSOLE Handle Input: cur_index=%d (mod=%d), avail_index=%d\n",
+ q->cur_avail_idx, q->cur_avail_idx % QUEUE_SIZE, q->avail->index);
+
+
+ if (q->cur_avail_idx != q->avail->index) {
+ uint16_t input_idx = q->avail->ring[q->cur_avail_idx % q->queue_size];
+ struct vring_desc * input_desc = NULL;
+ uint8_t * input_buf = NULL;
+
+
+ input_desc = &(q->desc[input_idx]);
+
+ if (v3_gpa_to_hva(&(cons_state->vm->cores[0]), input_desc->addr_gpa, (addr_t *)&(input_buf)) == -1) {
+ PrintError("Could not translate receive buffer address\n");
+ return 0;
+ }
+
+ memset(input_buf, 0, input_desc->length);
+
+ xfer_len = (input_desc->length > len) ? len : input_desc->length;
+
+ memcpy(input_buf, buf, xfer_len);
+
+
+ q->used->ring[q->used->index % q->queue_size].id = q->avail->ring[q->cur_avail_idx % q->queue_size];
+ q->used->ring[q->used->index % q->queue_size].length = xfer_len;
+
+ q->used->index++;
+ q->cur_avail_idx++;
+ }
+
+
+ // say hello
+ if (!(q->avail->flags & VIRTIO_NO_IRQ_FLAG)) {
+ v3_pci_raise_irq(cons_state->pci_bus, 0, cons_state->pci_dev);
+ cons_state->virtio_cfg.pci_isr = 0x1;
+ }
+
+ return xfer_len;
+}
+
+
+static int virtio_io_write(struct guest_info * core, uint16_t port, void * src, uint_t length, void * private_data) {
+ struct virtio_console_state * virtio = (struct virtio_console_state *)private_data;
+ int port_idx = port % virtio->io_range_size;
+
+
+ PrintDebug("VIRTIO CONSOLE Write for port %d (index=%d) len=%d, value=%x\n",
+ port, port_idx, length, *(uint32_t *)src);
+
+
+
+ switch (port_idx) {
+ case GUEST_FEATURES_PORT:
+ if (length != 4) {
+ PrintError("Illegal write length for guest features\n");
+ return -1;
+ }
+
+ virtio->virtio_cfg.guest_features = *(uint32_t *)src;
+
+ break;
+ case VRING_PG_NUM_PORT:
+ if (length == 4) {
+ addr_t pfn = *(uint32_t *)src;
+ addr_t page_addr = (pfn << VIRTIO_PAGE_SHIFT);
+
+
+ virtio->cur_queue->pfn = pfn;
+
+ virtio->cur_queue->ring_desc_addr = page_addr ;
+ virtio->cur_queue->ring_avail_addr = page_addr + (QUEUE_SIZE * sizeof(struct vring_desc));
+ virtio->cur_queue->ring_used_addr = ( virtio->cur_queue->ring_avail_addr + \
+ sizeof(struct vring_avail) + \
+ (QUEUE_SIZE * sizeof(uint16_t)));
+
+ // round up to next page boundary.
+ virtio->cur_queue->ring_used_addr = (virtio->cur_queue->ring_used_addr + 0xfff) & ~0xfff;
+
+ if (v3_gpa_to_hva(core, virtio->cur_queue->ring_desc_addr, (addr_t *)&(virtio->cur_queue->desc)) == -1) {
+ PrintError("Could not translate ring descriptor address\n");
+ return -1;
+ }
+
+
+ if (v3_gpa_to_hva(core, virtio->cur_queue->ring_avail_addr, (addr_t *)&(virtio->cur_queue->avail)) == -1) {
+ PrintError("Could not translate ring available address\n");
+ return -1;
+ }
+
+
+ if (v3_gpa_to_hva(core, virtio->cur_queue->ring_used_addr, (addr_t *)&(virtio->cur_queue->used)) == -1) {
+ PrintError("Could not translate ring used address\n");
+ return -1;
+ }
+
+ PrintDebug("RingDesc_addr=%p, Avail_addr=%p, Used_addr=%p\n",
+ (void *)(virtio->cur_queue->ring_desc_addr),
+ (void *)(virtio->cur_queue->ring_avail_addr),
+ (void *)(virtio->cur_queue->ring_used_addr));
+
+ PrintDebug("RingDesc=%p, Avail=%p, Used=%p\n",
+ virtio->cur_queue->desc, virtio->cur_queue->avail, virtio->cur_queue->used);
+
+ } else {
+ PrintError("Illegal write length for page frame number\n");
+ return -1;
+ }
+ break;
+ case VRING_Q_SEL_PORT:
+ virtio->virtio_cfg.vring_queue_selector = *(uint16_t *)src;
+
+ if (virtio->virtio_cfg.vring_queue_selector > 1) {
+ PrintError("Virtio Console device only uses 2 queue, selected %d\n",
+ virtio->virtio_cfg.vring_queue_selector);
+ return -1;
+ }
+
+ virtio->cur_queue = &(virtio->queue[virtio->virtio_cfg.vring_queue_selector]);
+
+ break;
+ case VRING_Q_NOTIFY_PORT:
+ PrintDebug("Handling Kick\n");
+ if (handle_kick(core, virtio) == -1) {
+ PrintError("Could not handle Console Notification\n");
+ return -1;
+ }
+ break;
+ case VIRTIO_STATUS_PORT:
+ virtio->virtio_cfg.status = *(uint8_t *)src;
+
+ if (virtio->virtio_cfg.status == 0) {
+ PrintDebug("Resetting device\n");
+ virtio_reset(virtio);
+ }
+
+ break;
+
+ case VIRTIO_ISR_PORT:
+ virtio->virtio_cfg.pci_isr = *(uint8_t *)src;
+ break;
+ default:
+ return -1;
+ break;
+ }
+
+ return length;
+}
+
+
+static int virtio_io_read(struct guest_info * core, uint16_t port, void * dst, uint_t length, void * private_data) {
+ struct virtio_console_state * virtio = (struct virtio_console_state *)private_data;
+ int port_idx = port % virtio->io_range_size;
+
+
+ PrintDebug("VIRTIO CONSOLE Read for port %d (index =%d), length=%d\n",
+ port, port_idx, length);
+
+ switch (port_idx) {
+ case HOST_FEATURES_PORT:
+ if (length != 4) {
+ PrintError("Illegal read length for host features\n");
+ return -1;
+ }
+
+ *(uint32_t *)dst = virtio->virtio_cfg.host_features;
+
+ break;
+ case VRING_PG_NUM_PORT:
+ if (length != 4) {
+ PrintError("Illegal read length for page frame number\n");
+ return -1;
+ }
+
+ *(uint32_t *)dst = virtio->cur_queue->pfn;
+
+ break;
+ case VRING_SIZE_PORT:
+ if (length != 2) {
+ PrintError("Illegal read length for vring size\n");
+ return -1;
+ }
+
+ *(uint16_t *)dst = virtio->cur_queue->queue_size;
+
+ break;
+
+ case VIRTIO_STATUS_PORT:
+ if (length != 1) {
+ PrintError("Illegal read length for status\n");
+ return -1;
+ }
+
+ *(uint8_t *)dst = virtio->virtio_cfg.status;
+ break;
+
+ case VIRTIO_ISR_PORT:
+ *(uint8_t *)dst = virtio->virtio_cfg.pci_isr;
+ virtio->virtio_cfg.pci_isr = 0;
+ v3_pci_lower_irq(virtio->pci_bus, 0, virtio->pci_dev);
+ break;
+
+ default:
+ if ( (port_idx >= sizeof(struct virtio_config)) &&
+ (port_idx < (sizeof(struct virtio_config) + sizeof(struct console_config))) ) {
+ int cfg_offset = port_idx - sizeof(struct virtio_config);
+ uint8_t * cfg_ptr = (uint8_t *)&(virtio->cons_cfg);
+
+ memcpy(dst, cfg_ptr + cfg_offset, length);
+
+ } else {
+ PrintError("Read of Unhandled Virtio Read\n");
+ return -1;
+ }
+
+ break;
+ }
+
+ return length;
+}
+
+
+
+
+static int connect_fn(struct v3_vm_info * vm,
+ void * frontend_data,
+ struct v3_dev_char_ops * ops,
+ v3_cfg_tree_t * cfg,
+ void * private_data,
+ void ** push_fn_arg) {
+
+ struct virtio_console_state * state = (struct virtio_console_state *)frontend_data;
+
+ state->ops = ops;
+ state->backend_data = private_data;
+
+ state->ops->input = virtio_input;
+ *push_fn_arg = state;
+
+ return 0;
+}
+
+static int virtio_free(struct virtio_console_state * virtio) {
+
+ // unregister from PCI
+
+ V3_Free(virtio);
+ return 0;
+}
+
+
+static struct v3_device_ops dev_ops = {
+ .free = (int (*)(void *))virtio_free,
+
+};
+
+
+
+
+static int virtio_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
+ struct vm_device * pci_bus = v3_find_dev(vm, v3_cfg_val(cfg, "bus"));
+ struct virtio_console_state * virtio_state = NULL;
+ struct pci_device * pci_dev = NULL;
+ char * dev_id = v3_cfg_val(cfg, "ID");
+
+ PrintDebug("Initializing VIRTIO Console device\n");
+
+ if (pci_bus == NULL) {
+ PrintError("VirtIO devices require a PCI Bus");
+ return -1;
+ }
+
+
+ virtio_state = (struct virtio_console_state *)V3_Malloc(sizeof(struct virtio_console_state));
+ memset(virtio_state, 0, sizeof(struct virtio_console_state));
+
+
+ cons_state = virtio_state;
+ cons_state->vm = vm;
+
+
+
+ struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, virtio_state);
+
+ if (dev == NULL) {
+ PrintError("Could not attach device %s\n", dev_id);
+ V3_Free(virtio_state);
+ return -1;
+ }
+
+ // PCI initialization
+ {
+ struct v3_pci_bar bars[6];
+ int num_ports = sizeof(struct virtio_config) + sizeof(struct console_config);
+ int tmp_ports = num_ports;
+ int i;
+
+
+ // This gets the number of ports, rounded up to a power of 2
+ virtio_state->io_range_size = 1; // must be a power of 2
+
+ while (tmp_ports > 0) {
+ tmp_ports >>= 1;
+ virtio_state->io_range_size <<= 1;
+ }
+
+ // this is to account for any low order bits being set in num_ports
+ // if there are none, then num_ports was already a power of 2 so we shift right to reset it
+ if ((num_ports & ((virtio_state->io_range_size >> 1) - 1)) == 0) {
+ virtio_state->io_range_size >>= 1;
+ }
+
+
+ for (i = 0; i < 6; i++) {
+ bars[i].type = PCI_BAR_NONE;
+ }
+
+ bars[0].type = PCI_BAR_IO;
+ bars[0].default_base_port = -1;
+ bars[0].num_ports = virtio_state->io_range_size;
+
+ bars[0].io_read = virtio_io_read;
+ bars[0].io_write = virtio_io_write;
+ bars[0].private_data = virtio_state;
+
+
+ pci_dev = v3_pci_register_device(pci_bus, PCI_STD_DEVICE,
+ 0, PCI_AUTO_DEV_NUM, 0,
+ "LNX_VIRTIO_CONSOLE", bars,
+ NULL, NULL, NULL, virtio_state);
+
+ if (!pci_dev) {
+ PrintError("Could not register PCI Device\n");
+ v3_remove_device(dev);
+ return -1;
+ }
+
+ pci_dev->config_header.vendor_id = VIRTIO_VENDOR_ID;
+ pci_dev->config_header.subsystem_vendor_id = VIRTIO_SUBVENDOR_ID;
+
+
+ pci_dev->config_header.device_id = VIRTIO_CONSOLE_DEV_ID;
+ pci_dev->config_header.class = PCI_CLASS_DISPLAY;
+ pci_dev->config_header.subclass = PCI_DISPLAY_SUBCLASS_OTHER;
+
+ pci_dev->config_header.subsystem_id = VIRTIO_CONSOLE_SUBDEVICE_ID;
+
+ pci_dev->config_header.intr_pin = 1;
+
+ pci_dev->config_header.max_latency = 1; // ?? (qemu does it...)
+
+
+ virtio_state->pci_dev = pci_dev;
+ virtio_state->pci_bus = pci_bus;
+ }
+
+ virtio_reset(virtio_state);
+
+ if (v3_dev_add_char_frontend(vm, dev_id, connect_fn, (void *)virtio_state) == -1) {
+ PrintError("Could not register %s as frontend\n", dev_id);
+ v3_remove_device(dev);
+ return -1;
+ }
+
+
+ return 0;
+}
+
+
+device_register("LNX_VIRTIO_CONSOLE", virtio_init)
{
uint8_t * buf = NULL;
uint32_t len = buf_desc->length;
- int synchronize = virtio->tx_notify;
if (v3_gpa_to_hva(core, buf_desc->addr_gpa, (addr_t *)&(buf)) == -1) {
PrintDebug("Could not translate buffer address\n");
v3_hexdump(buf, len, NULL, 0);
}
- if(virtio->net_ops->send(buf, len, synchronize, virtio->backend_data) < 0){
+ if(virtio->net_ops->send(buf, len, virtio->backend_data) < 0){
virtio->stats.tx_dropped ++;
return -1;
}
}
static int handle_pkt_tx(struct guest_info * core,
- struct virtio_net_state * virtio_state)
+ struct virtio_net_state * virtio_state,
+ int quote)
{
struct virtio_queue *q = &(virtio_state->tx_vq);
- int txed = 0;
- unsigned long flags;
+ int txed = 0, left = 0;
+ unsigned long flags;
if (!q->ring_avail_addr) {
return -1;
q->used->index ++;
q->cur_avail_idx ++;
-
- txed ++;
+
+ if(++txed >= quote && quote > 0){
+ left = (q->cur_avail_idx != q->avail->index);
+ break;
+ }
}
v3_unlock_irqrestore(virtio_state->tx_lock, flags);
virtio_state->stats.rx_interrupts ++;
}
+ V3_Print("Virtio Intr Line %d\n", virtio_state->pci_dev->config_header.intr_line);
+
if(txed > 0) {
- V3_Net_Print(2, "Virtio Handle TX: txed pkts: %d\n", txed);
+ V3_Net_Print(2, "Virtio Handle TX: txed pkts: %d, left %d\n", txed, left);
}
- return 0;
+ return left;
exit_error:
/* receive queue refill */
virtio->stats.tx_interrupts ++;
} else if (queue_idx == 1){
- if (handle_pkt_tx(core, virtio) == -1) {
- PrintError("Could not handle Virtio NIC tx kick\n");
+ if (handle_pkt_tx(core, virtio, 0) < 0) {
+ PrintError("Virtio NIC: Error to handle packet TX\n");
return -1;
}
virtio->stats.tx_interrupts ++;
} else if (queue_idx == 2){
/* ctrl */
} else {
- PrintError("Wrong queue index %d\n", queue_idx);
+ PrintError("Virtio NIC: Wrong queue index %d\n", queue_idx);
}
break;
}
switch (port_idx) {
case HOST_FEATURES_PORT:
if (length != 4) {
- PrintError("Illegal read length for host features\n");
+ PrintError("Virtio NIC: Illegal read length for host features\n");
//return -1;
}
*(uint32_t *)dst = virtio->virtio_cfg.host_features;
case VRING_PG_NUM_PORT:
if (length != 4) {
- PrintError("Illegal read length for page frame number\n");
+ PrintError("Virtio NIC: Illegal read length for page frame number\n");
return -1;
}
switch (queue_idx) {
case VRING_SIZE_PORT:
if (length != 2) {
- PrintError("Illegal read length for vring size\n");
+ PrintError("Virtio NIC: Illegal read length for vring size\n");
return -1;
}
switch (queue_idx) {
case VIRTIO_STATUS_PORT:
if (length != 1) {
- PrintError("Illegal read length for status\n");
+ PrintError("Virtio NIC: Illegal read length for status\n");
return -1;
}
*(uint8_t *)dst = virtio->virtio_cfg.status;
unsigned long flags;
uint8_t kick_guest = 0;
- V3_Net_Print(2, "Virtio-NIC: virtio_rx: size: %d\n", size);
+ V3_Net_Print(2, "Virtio NIC: virtio_rx: size: %d\n", size);
if (!q->ring_avail_addr) {
V3_Net_Print(2, "Virtio NIC: RX Queue not set\n");
len = copy_data_to_desc(&(virtio->virtio_dev->vm->cores[0]),
virtio, buf_desc, buf+offset, size-offset, 0);
if (len < 0){
- V3_Net_Print(2, "Virtio NIC:merged buffer, %d buffer size %d\n",
+ V3_Net_Print(2, "Virtio NIC: merged buffer, %d buffer size %d\n",
hdr.num_buffers, len);
q->cur_avail_idx = old_idx;
goto err_exit;
};
-static int virtio_tx_flush(void * args){
- struct virtio_net_state *virtio = (struct virtio_net_state *)args;
+static int virtio_poll(int quote, void * data){
+ struct virtio_net_state * virtio = (struct virtio_net_state *)data;
- V3_Print("Virtio TX Poll Thread Starting for %s\n",
- virtio->vm->name);
-
- while(1){
- if(virtio->tx_notify == 0){
- handle_pkt_tx(&(virtio->vm->cores[0]), virtio);
- v3_yield(NULL);
- }else {
- vnet_thread_sleep(-1);
- }
- }
-
- return 0;
+ return handle_pkt_tx(&(virtio->vm->cores[0]), virtio, quote);
}
static int register_dev(struct virtio_dev_state * virtio,
int i;
/* This gets the number of ports, rounded up to a power of 2 */
- net_state->io_range_size = 1; // must be a power of 2
+ net_state->io_range_size = 1;
while (tmp_ports > 0) {
tmp_ports >>= 1;
net_state->io_range_size <<= 1;
bars[i].type = PCI_BAR_NONE;
}
- PrintDebug("Virtio-NIC io_range_size = %d\n",
+ PrintDebug("Virtio NIC: io_range_size = %d\n",
net_state->io_range_size);
bars[0].type = PCI_BAR_IO;
bars[0].private_data = net_state;
pci_dev = v3_pci_register_device(virtio->pci_bus, PCI_STD_DEVICE,
- 0, 4/*PCI_AUTO_DEV_NUM*/, 0,
+ 0, PCI_AUTO_DEV_NUM, 0,
"LNX_VIRTIO_NIC", bars,
NULL, NULL, NULL, net_state);
virtio_init_state(net_state);
+ V3_Print("Virtio NIC: Registered Intr Line %d\n", pci_dev->config_header.intr_line);
+
/* Add backend to list of devices */
list_add(&(net_state->dev_link), &(virtio->dev_list));
&timer_ops,net_state);
ops->recv = virtio_rx;
- ops->frontend_data = net_state;
- memcpy(ops->fnt_mac, virtio->mac, ETH_ALEN);
-
- net_state->poll_thread = vnet_start_thread(virtio_tx_flush,
- (void *)net_state, "Virtio_Poll");
+ ops->poll = virtio_poll;
+ ops->config.frontend_data = net_state;
+ ops->config.poll = 1;
+ ops->config.quote = 64;
+ ops->config.fnt_mac = V3_Malloc(ETH_ALEN);
+ memcpy(ops->config.fnt_mac, virtio->mac, ETH_ALEN);
net_state->status = 1;
memcpy(macstr, str, strlen(str));
if (pci_bus == NULL) {
- PrintError("Virtio NIC: VirtIO devices require a PCI Bus");
+ PrintError("Virtio NIC: Virtio device require a PCI Bus");
return -1;
}
}
-//irq is pirq_rc[intr_pin + pci_dev_num - 1] & 0x3
+//irq is pirq_rc[intr_pin + pci_dev_num - 1] & 0xf
+/*
+struct pirq_rc_reg {
+ uint8_t irq : 4;
+ uint8_t rsvd : 3;
+ uint8_t disabled : 1; // (1=disabled, 0=enabled)
+}
+*/
+
static int raise_pci_irq(struct pci_device * pci_dev, void * dev_data) {
struct v3_southbridge * piix3 = dev_data;
//PrintError("Raising PCI IRQ %d, %p\n", piix3_cfg->pirq_rc[irq_index], piix3->vm);
- v3_raise_irq(piix3->vm, piix3_cfg->pirq_rc[irq_index]);
+ if (piix3_cfg->pirq_rc[irq_index] < 16) {
+ v3_raise_irq(piix3->vm, piix3_cfg->pirq_rc[irq_index] & 0xf);
+ } else {
+ PrintError("Tried to raise interrupt on disabled PIRQ entry (%d)\n", irq_index);
+ PrintError("\tpirq_rc values: 0=0x%x, 1=0x%x, 2=0x%x, 3=0x%x\n",
+ piix3_cfg->pirq_rc[0], piix3_cfg->pirq_rc[1],
+ piix3_cfg->pirq_rc[2], piix3_cfg->pirq_rc[3]);
+ return -1;
+ }
return 0;
}
// PrintError("Lowering PCI IRQ %d\n", piix3_cfg->pirq_rc[irq_index]);
- v3_lower_irq(piix3->vm, piix3_cfg->pirq_rc[irq_index]);
+ if (piix3_cfg->pirq_rc[irq_index] < 16) {
+ v3_lower_irq(piix3->vm, piix3_cfg->pirq_rc[irq_index] & 0xf);
+ } else {
+ PrintError("Tried to lower interrupt on disabled PIRQ entry (%d)\n", irq_index);
+ PrintError("\tpirq_rc values: 0=0x%x, 1=0x%x, 2=0x%x, 3=0x%x\n",
+ piix3_cfg->pirq_rc[0], piix3_cfg->pirq_rc[1],
+ piix3_cfg->pirq_rc[2], piix3_cfg->pirq_rc[3]);
+ return -1;
+ }
return 0;
}
com->lsr.oe = 1; //overrun error bit set
}
+ updateIRQ(vm, com);
+
return 0;
}
com->lsr.thre = 0; //reset thre and temt bits.
com->lsr.temt = 0;
}
-
- updateIRQ(vm, com);
-
+
return 0;
}
/* JRL: Some buffering would probably be a good idea here.... */
if (com_port->ops) {
- com_port->ops->write(val, 1, com_port->backend_data);
+ com_port->ops->output(val, 1, com_port->backend_data);
} else {
queue_data(core->vm_info, com_port, &(com_port->tx_buffer), *val);
+ updateIRQ(core->vm_info, com_port);
}
}
return 0;
}
-static int serial_input(struct v3_vm_info * vm, uint8_t * buf, uint64_t len, void * priv_data){
+static uint64_t serial_input(struct v3_vm_info * vm, uint8_t * buf, uint64_t len, void * priv_data){
struct serial_port * com_port = (struct serial_port *)priv_data;
int i;
queue_data(vm, com_port, &(com_port->rx_buffer), buf[i]);
}
+ updateIRQ(vm, com_port);
+
return len;
}
com->ops = ops;
com->backend_data = private_data;
- com->ops->push = serial_input;
+ com->ops->input = serial_input;
*push_fn_arg = com;
return 0;
/* called by frontend, send pkt to VNET */
static int vnet_nic_send(uint8_t * buf, uint32_t len,
- int synchronize, void * private_data) {
+ void * private_data) {
struct vnet_nic_state * vnetnic = (struct vnet_nic_state *)private_data;
struct v3_vnet_pkt pkt;
v3_hexdump(buf, len, NULL, 0);
}
- return v3_vnet_send_pkt(&pkt, NULL, synchronize);
+ return v3_vnet_send_pkt(&pkt, NULL);
}
/* send pkt to frontend device */
-static int virtio_input(struct v3_vm_info * info,
+static int fnt_input(struct v3_vm_info * info,
struct v3_vnet_pkt * pkt,
void * private_data){
struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
pkt->size, pkt->src_id, pkt->src_type, pkt->dst_id, pkt->dst_type);
return vnetnic->net_ops.recv(pkt->data, pkt->size,
- vnetnic->net_ops.frontend_data);
+ vnetnic->net_ops.config.frontend_data);
+}
+
+
+/* poll pkt from frontend device */
+static int fnt_poll(struct v3_vm_info * info,
+ int quote, void * private_data){
+ struct vnet_nic_state *vnetnic = (struct vnet_nic_state *)private_data;
+
+ return vnetnic->net_ops.poll(quote, vnetnic->net_ops.config.frontend_data);
}
};
static struct v3_vnet_dev_ops vnet_dev_ops = {
- .input = virtio_input,
+ .input = fnt_input,
+ .poll = fnt_poll,
};
}
PrintDebug("Vnet-nic: Connect %s to frontend %s\n",
- dev_id, v3_cfg_val(frontend_cfg, "tag"));
+ dev_id, v3_cfg_val(frontend_cfg, "tag"));
- if ((vnet_dev_id = v3_vnet_add_dev(vm, vnetnic->net_ops.fnt_mac, &vnet_dev_ops, (void *)vnetnic)) == -1) {
+ if ((vnet_dev_id = v3_vnet_add_dev(vm, vnetnic->net_ops.config.fnt_mac,
+ &vnet_dev_ops, vnetnic->net_ops.config.quote,
+ vnetnic->net_ops.config.poll, (void *)vnetnic)) == -1) {
PrintError("Vnet-nic device %s fails to registered to VNET\n", dev_id);
v3_remove_device(dev);
return 0;
}
+int v3_mcheck_inject_scrubber_mce(struct v3_vm_info *info, int cpu, uint64_t dst)
+{
+ struct mc4_stat_msr stat;
+ struct mc4_addr_msr addr;
+
+ stat.value = 0;
+ stat.error_code = 0x810;
+ stat.error_code_ext = 0x8;
+ stat.uecc = 1;
+ stat.addr_v = 1;
+ stat.en = 1;
+ stat.uc = 1;
+ stat.val = 1;
+
+ addr.addr64 = dst;
+
+ return v3_mcheck_inject_nb_mce(info, cpu, stat, addr);
+}
+
static struct v3_extension_impl mcheck_impl = {
.name = MCHECK,
.init = init_mcheck,
--- /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) 2008, Jack Lange <jarusl@cs.northwestern.edu>
+ * Copyright (c) 2008, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jarusl@cs.northwestern.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm.h>
+#include <palacios/vmm_extensions.h>
+#include <palacios/vmm_msr.h>
+
+
+
+#define MTRR_CAP 0xfe
+
+#define MTRR_PHYS_BASE_0 0x200
+#define MTRR_PHYS_MASK_0 0x201
+#define MTRR_PHYS_BASE_1 0x202
+#define MTRR_PHYS_MASK_1 0x203
+#define MTRR_PHYS_BASE_2 0x204
+#define MTRR_PHYS_MASK_2 0x205
+#define MTRR_PHYS_BASE_3 0x206
+#define MTRR_PHYS_MASK_3 0x207
+#define MTRR_PHYS_BASE_4 0x208
+#define MTRR_PHYS_MASK_4 0x209
+#define MTRR_PHYS_BASE_5 0x20a
+#define MTRR_PHYS_MASK_5 0x20b
+#define MTRR_PHYS_BASE_6 0x20c
+#define MTRR_PHYS_MASK_6 0x20d
+#define MTRR_PHYS_BASE_7 0x20e
+#define MTRR_PHYS_MASK_7 0x20f
+
+#define MTRR_FIX_64K_00000 0x250
+#define MTRR_FIX_16K_80000 0x258
+#define MTRR_FIX_16K_A0000 0x259
+#define MTRR_FIX_4K_C0000 0x268
+#define MTRR_FIX_4K_C8000 0x269
+#define MTRR_FIX_4K_D0000 0x26a
+#define MTRR_FIX_4K_D8000 0x26b
+#define MTRR_FIX_4K_E0000 0x26c
+#define MTRR_FIX_4K_E8000 0x26d
+#define MTRR_FIX_4K_F0000 0x26e
+#define MTRR_FIX_4K_F8000 0x26f
+
+#define PAT 0x277
+
+#define MTRR_DEF_TYPE 0x2ff
+
+
+
+
+struct ia32_pat {
+ union {
+ uint64_t value;
+
+ struct {
+ uint64_t pa_0 : 3;
+ uint64_t rsvd0 : 5;
+ uint64_t pa_1 : 3;
+ uint64_t rsvd1 : 5;
+ uint64_t pa_2 : 3;
+ uint64_t rsvd2 : 5;
+ uint64_t pa_3 : 3;
+ uint64_t rsvd3 : 5;
+ uint64_t pa_4 : 3;
+ uint64_t rsvd4 : 5;
+ uint64_t pa_5 : 3;
+ uint64_t rsvd5 : 5;
+ uint64_t pa_6 : 3;
+ uint64_t rsvd6 : 5;
+ uint64_t pa_7 : 3;
+ uint64_t rsvd7 : 5;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct mtrr_cap {
+ union {
+ uint64_t value;
+
+ struct {
+ uint64_t var_reg_cnt : 8;
+ uint64_t fix : 1;
+ uint64_t rsvd0 : 1;
+ uint64_t wr_combine : 1;
+ uint64_t rsvd1 : 53;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+struct mtrr_def_type {
+ union {
+ uint64_t value;
+
+ struct {
+ uint64_t def_type : 8;
+ uint64_t rsvd0 : 2;
+ uint64_t fixed_enable : 1;
+ uint64_t mtrr_emable : 1;
+ uint64_t rsvd1 : 52;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct mtrr_phys_base {
+ union {
+ uint64_t value;
+
+ struct {
+ uint64_t type : 8;
+ uint64_t rsvd0 : 4;
+ uint64_t base : 40;
+ uint64_t rsvd1 : 12;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct mtrr_phys_mask {
+ union {
+ uint64_t value;
+
+ struct {
+ uint64_t rsvd0 : 11;
+ uint64_t valid : 1;
+ uint64_t mask : 40;
+ uint64_t rsvd1 : 12;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+struct mtrr_fixed {
+ union {
+ uint64_t value;
+ uint8_t types[8];
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+/* AMD Specific Registers */
+#define SYSCONFIG 0xc0010010
+#define TOP_MEM 0xc001001a
+#define TOP_MEM2 0xc001001d
+
+#define IORR_BASE0 0xc0010016
+#define IORR_MASK0 0xc0010017
+#define IORR_BASE1 0xc0010018
+#define IORR_MASK1 0xc0010019
+
+struct syscfg_reg {
+ union {
+ uint64_t value;
+
+ struct {
+ uint64_t rsvd0 : 18;
+ uint64_t mfde : 1; // 1 = enables RdMem and WrMem bits in fixed-range MTRRs
+ uint64_t mfdm : 1; // 1 = software can modify RdMem and WrMem bits
+ uint64_t mvdm : 1; // 1 = enables TOP_MEM reg and var range MTRRs
+ uint64_t tom2 : 1; // 1 = enables TOP_MEM2 reg
+ uint64_t tom2_force_wb : 1; // 1 = enables default mem type for 4GB-TOP_MEM2 range
+ uint64_t rsvd1 : 41;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+struct top_of_mem_reg {
+ union {
+ uint64_t value;
+
+ struct {
+ uint64_t rsvd0 : 23;
+ uint64_t phys_addr : 29;
+ uint64_t rsvd1 : 12;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+struct iorr_base {
+ union {
+ uint64_t value;
+
+ struct {
+ uint64_t rsvd0 : 3;
+ uint64_t wrmem : 1; // 1 = writes go to memory, 0 = writes go to mmap IO
+ uint64_t rdmem : 1; // 1 = reads go to memory, 0 = reads go to mmap IO
+ uint64_t rsvd1 : 7;
+ uint64_t base : 40;
+ uint64_t rsvd2 : 12;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+struct iorr_mask {
+ union {
+ uint64_t value;
+
+ struct {
+ uint64_t rsvd0 : 11;
+ uint64_t valid : 1;
+ uint64_t mask : 40;
+ uint64_t rsvd1 : 12;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+/* Intel Specific Registers */
+#define SMRR_PHYS_BASE 0x1f2
+#define SMRR_PHYS_MASK 0x1f3
+
+struct smrr_phys_base {
+ union {
+ uint64_t value;
+
+ struct {
+ uint64_t type : 8;
+ uint64_t rsvd0 : 4;
+ uint64_t base : 20;
+ uint64_t rsvd1 : 32;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+struct smrr_phys_mask {
+ union {
+ uint64_t value;
+
+ struct {
+ uint64_t rsvd0 : 11;
+ uint64_t valid : 1;
+ uint64_t mask : 20;
+ uint64_t rsvd1 : 32;
+ } __attribute__((packed));
+ } __attribute__((packed));
+} __attribute__((packed));
+
+
+
+struct mtrr_state {
+ struct ia32_pat pat;
+ struct mtrr_cap cap;
+ struct mtrr_def_type def_type;
+ struct mtrr_phys_base bases[8];
+ struct mtrr_phys_mask masks[8];
+
+ struct mtrr_fixed fixed_64k;
+ struct mtrr_fixed fixed_16k[2];
+ struct mtrr_fixed fixed_4k[8];
+
+ /* AMD specific registers */
+ struct syscfg_reg amd_syscfg;
+ struct top_of_mem_reg amd_tom;
+ struct top_of_mem_reg amd_tom2;
+
+ struct iorr_base iorr_bases[2];
+ struct iorr_mask iorr_masks[2];
+
+ /* Intel Specific registers */
+ struct smrr_phys_base intel_smrr_base;
+ struct smrr_phys_mask intel_smrr_mask;
+
+};
+
+static void init_state(struct mtrr_state * state) {
+ state->pat.value = 0x0007040600070406LL;
+ state->cap.value = 0x0000000000000508LL;
+
+ state->amd_syscfg.value = 0x0000000000020601LL;
+ state->amd_tom.value = 0x0000000004000000LL;
+
+ return;
+}
+
+static int mtrr_cap_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ dst->value = state->cap.value;
+ return 0;
+}
+
+static int mtrr_cap_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ state->cap.value = src.value;
+ return 0;
+}
+
+static int pat_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ dst->value = state->pat.value;
+ return 0;
+}
+
+static int pat_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ state->pat.value = src.value;
+ return 0;
+}
+
+static int def_type_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ dst->value = state->def_type.value;
+ return 0;
+}
+
+static int def_type_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ state->def_type.value = src.value;
+ return 0;
+}
+
+
+static int mtrr_phys_base_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int base_index = (msr - MTRR_PHYS_BASE_0) / 2;
+ dst->value = state->bases[base_index].value;
+ return 0;
+}
+
+static int mtrr_phys_base_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int base_index = (msr - MTRR_PHYS_BASE_0) / 2;
+ state->bases[base_index].value = src.value;
+ return 0;
+}
+
+static int mtrr_phys_mask_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int mask_index = (msr - MTRR_PHYS_MASK_0) / 2;
+ dst->value = state->masks[mask_index].value;
+ return 0;
+}
+
+static int mtrr_phys_mask_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int mask_index = (msr - MTRR_PHYS_MASK_0) / 2;
+ state->masks[mask_index].value = src.value;
+ return 0;
+}
+
+static int mtrr_fix_64k_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ dst->value = state->fixed_64k.value;
+ return 0;
+}
+
+static int mtrr_fix_64k_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ state->fixed_64k.value = src.value;
+ return 0;
+}
+
+static int mtrr_fix_16k_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int index = msr - MTRR_FIX_16K_80000;
+ dst->value = state->fixed_16k[index].value;
+ return 0;
+}
+
+static int mtrr_fix_16k_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int index = msr - MTRR_FIX_16K_80000;
+ state->fixed_16k[index].value = src.value;
+ return 0;
+}
+
+static int mtrr_fix_4k_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int index = msr - MTRR_FIX_4K_C0000;
+ dst->value = state->fixed_4k[index].value;
+ return 0;
+}
+
+static int mtrr_fix_4k_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int index = msr - MTRR_FIX_4K_C0000;
+ state->fixed_4k[index].value = src.value;
+ return 0;
+}
+
+/* AMD specific registers */
+static int amd_syscfg_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ dst->value = state->amd_syscfg.value;
+ return 0;
+}
+
+static int amd_syscfg_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ state->amd_syscfg.value = src.value;
+ return 0;
+}
+
+static int amd_top_mem_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+
+ if (msr == TOP_MEM) {
+ dst->value = state->amd_tom.value;
+ } else if (msr == TOP_MEM2) {
+ dst->value = state->amd_tom2.value;
+ }
+
+ return 0;
+}
+
+static int amd_top_mem_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+
+ if (msr == TOP_MEM) {
+ state->amd_tom.value = src.value;
+ } else if (msr == TOP_MEM2) {
+ state->amd_tom2.value = src.value;
+ }
+
+ return 0;
+}
+
+
+static int amd_iorr_base_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int base_index = (msr - IORR_BASE0) / 2;
+ dst->value = state->iorr_bases[base_index].value;
+ return 0;
+}
+
+static int amd_iorr_base_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int base_index = (msr - IORR_BASE0) / 2;
+ state->iorr_bases[base_index].value = src.value;
+ return 0;
+}
+
+static int amd_iorr_mask_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int mask_index = (msr - IORR_MASK0) / 2;
+ dst->value = state->iorr_masks[mask_index].value;
+ return 0;
+}
+
+static int amd_iorr_mask_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ int mask_index = (msr - IORR_MASK0) / 2;
+ state->iorr_masks[mask_index].value = src.value;
+ return 0;
+}
+
+
+static int intel_smrr_base_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ dst->value = state->intel_smrr_base.value;
+ return 0;
+}
+
+static int intel_smrr_base_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ state->intel_smrr_base.value = src.value;
+ return 0;
+}
+
+static int intel_smrr_mask_read(struct guest_info * core, uint_t msr, v3_msr_t * dst, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ dst->value = state->intel_smrr_mask.value;
+ return 0;
+}
+
+static int intel_smrr_mask_write(struct guest_info * core, uint_t msr, v3_msr_t src, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+ state->intel_smrr_mask.value = src.value;
+ return 0;
+}
+
+
+static int deinit_mtrrs(struct v3_vm_info * vm, void * priv_data) {
+ struct mtrr_state * state = (struct mtrr_state *)priv_data;
+
+ v3_unhook_msr(vm, MTRR_CAP);
+ v3_unhook_msr(vm, PAT);
+ v3_unhook_msr(vm, MTRR_DEF_TYPE);
+
+ v3_unhook_msr(vm, MTRR_PHYS_BASE_0);
+ v3_unhook_msr(vm, MTRR_PHYS_BASE_1);
+ v3_unhook_msr(vm, MTRR_PHYS_BASE_2);
+ v3_unhook_msr(vm, MTRR_PHYS_BASE_3);
+ v3_unhook_msr(vm, MTRR_PHYS_BASE_4);
+ v3_unhook_msr(vm, MTRR_PHYS_BASE_5);
+ v3_unhook_msr(vm, MTRR_PHYS_BASE_6);
+ v3_unhook_msr(vm, MTRR_PHYS_BASE_7);
+ v3_unhook_msr(vm, MTRR_PHYS_MASK_0);
+ v3_unhook_msr(vm, MTRR_PHYS_MASK_1);
+ v3_unhook_msr(vm, MTRR_PHYS_MASK_2);
+ v3_unhook_msr(vm, MTRR_PHYS_MASK_3);
+ v3_unhook_msr(vm, MTRR_PHYS_MASK_4);
+ v3_unhook_msr(vm, MTRR_PHYS_MASK_5);
+ v3_unhook_msr(vm, MTRR_PHYS_MASK_6);
+ v3_unhook_msr(vm, MTRR_PHYS_MASK_7);
+
+ v3_unhook_msr(vm, MTRR_FIX_64K_00000);
+ v3_unhook_msr(vm, MTRR_FIX_16K_80000);
+ v3_unhook_msr(vm, MTRR_FIX_16K_A0000);
+ v3_unhook_msr(vm, MTRR_FIX_4K_C0000);
+ v3_unhook_msr(vm, MTRR_FIX_4K_C8000);
+ v3_unhook_msr(vm, MTRR_FIX_4K_D0000);
+ v3_unhook_msr(vm, MTRR_FIX_4K_D8000);
+ v3_unhook_msr(vm, MTRR_FIX_4K_E0000);
+ v3_unhook_msr(vm, MTRR_FIX_4K_E8000);
+ v3_unhook_msr(vm, MTRR_FIX_4K_F0000);
+ v3_unhook_msr(vm, MTRR_FIX_4K_F8000);
+
+ /* AMD specific */
+ v3_unhook_msr(vm, SYSCONFIG);
+ v3_unhook_msr(vm, TOP_MEM);
+ v3_unhook_msr(vm, TOP_MEM2);
+
+ v3_unhook_msr(vm, IORR_BASE0);
+ v3_unhook_msr(vm, IORR_BASE1);
+ v3_unhook_msr(vm, IORR_MASK0);
+ v3_unhook_msr(vm, IORR_MASK1);
+
+ /* Intel Specfic */
+ v3_unhook_msr(vm, SMRR_PHYS_BASE);
+ v3_unhook_msr(vm, SMRR_PHYS_MASK);
+
+
+ V3_Free(state);
+ return 0;
+}
+
+
+static int init_mtrrs(struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) {
+ struct mtrr_state * state = NULL;
+ int ret = 0;
+
+ state = V3_Malloc(sizeof(struct mtrr_state));
+ memset(state, 0, sizeof(struct mtrr_state));
+
+ *priv_data = state;
+
+ init_state(state);
+
+ // hook MSRs
+ ret |= v3_hook_msr(vm, MTRR_CAP, mtrr_cap_read, mtrr_cap_write, state);
+ ret |= v3_hook_msr(vm, PAT, pat_read, pat_write, state);
+ ret |= v3_hook_msr(vm, MTRR_DEF_TYPE, def_type_read, def_type_write, state);
+
+ ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_0, mtrr_phys_base_read, mtrr_phys_base_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_1, mtrr_phys_base_read, mtrr_phys_base_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_2, mtrr_phys_base_read, mtrr_phys_base_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_3, mtrr_phys_base_read, mtrr_phys_base_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_4, mtrr_phys_base_read, mtrr_phys_base_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_5, mtrr_phys_base_read, mtrr_phys_base_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_6, mtrr_phys_base_read, mtrr_phys_base_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_BASE_7, mtrr_phys_base_read, mtrr_phys_base_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_0, mtrr_phys_mask_read, mtrr_phys_mask_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_1, mtrr_phys_mask_read, mtrr_phys_mask_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_2, mtrr_phys_mask_read, mtrr_phys_mask_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_3, mtrr_phys_mask_read, mtrr_phys_mask_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_4, mtrr_phys_mask_read, mtrr_phys_mask_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_5, mtrr_phys_mask_read, mtrr_phys_mask_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_6, mtrr_phys_mask_read, mtrr_phys_mask_write, state);
+ ret |= v3_hook_msr(vm, MTRR_PHYS_MASK_7, mtrr_phys_mask_read, mtrr_phys_mask_write, state);
+
+ ret |= v3_hook_msr(vm, MTRR_FIX_64K_00000, mtrr_fix_64k_read, mtrr_fix_64k_write, state);
+ ret |= v3_hook_msr(vm, MTRR_FIX_16K_80000, mtrr_fix_16k_read, mtrr_fix_16k_write, state);
+ ret |= v3_hook_msr(vm, MTRR_FIX_16K_A0000, mtrr_fix_16k_read, mtrr_fix_16k_write, state);
+ ret |= v3_hook_msr(vm, MTRR_FIX_4K_C0000, mtrr_fix_4k_read, mtrr_fix_4k_write, state);
+ ret |= v3_hook_msr(vm, MTRR_FIX_4K_C8000, mtrr_fix_4k_read, mtrr_fix_4k_write, state);
+ ret |= v3_hook_msr(vm, MTRR_FIX_4K_D0000, mtrr_fix_4k_read, mtrr_fix_4k_write, state);
+ ret |= v3_hook_msr(vm, MTRR_FIX_4K_D8000, mtrr_fix_4k_read, mtrr_fix_4k_write, state);
+ ret |= v3_hook_msr(vm, MTRR_FIX_4K_E0000, mtrr_fix_4k_read, mtrr_fix_4k_write, state);
+ ret |= v3_hook_msr(vm, MTRR_FIX_4K_E8000, mtrr_fix_4k_read, mtrr_fix_4k_write, state);
+ ret |= v3_hook_msr(vm, MTRR_FIX_4K_F0000, mtrr_fix_4k_read, mtrr_fix_4k_write, state);
+ ret |= v3_hook_msr(vm, MTRR_FIX_4K_F8000, mtrr_fix_4k_read, mtrr_fix_4k_write, state);
+
+ /* AMD Specific */
+ ret |= v3_hook_msr(vm, SYSCONFIG, amd_syscfg_read, amd_syscfg_write, state);
+ ret |= v3_hook_msr(vm, TOP_MEM, amd_top_mem_read, amd_top_mem_write, state);
+ ret |= v3_hook_msr(vm, TOP_MEM2, amd_top_mem_read, amd_top_mem_write, state);
+
+ ret |= v3_hook_msr(vm, IORR_BASE0, amd_iorr_base_read, amd_iorr_base_write, state);
+ ret |= v3_hook_msr(vm, IORR_BASE1, amd_iorr_base_read, amd_iorr_base_write, state);
+ ret |= v3_hook_msr(vm, IORR_MASK0, amd_iorr_mask_read, amd_iorr_mask_write, state);
+ ret |= v3_hook_msr(vm, IORR_MASK1, amd_iorr_mask_read, amd_iorr_mask_write, state);
+
+
+ /* INTEL specific */
+ ret |= v3_hook_msr(vm, SMRR_PHYS_BASE, intel_smrr_base_read, intel_smrr_base_write, state);
+ ret |= v3_hook_msr(vm, SMRR_PHYS_MASK, intel_smrr_mask_read, intel_smrr_mask_write, state);
+
+ if (ret != 0) {
+ PrintError("Failed to hook all MTRR MSRs. Aborting...\n");
+ deinit_mtrrs(vm, state);
+ return -1;
+ }
+
+
+ return 0;
+}
+
+
+
+
+static struct v3_extension_impl mtrr_impl = {
+ .name = "MTRRS",
+ .init = init_mtrrs,
+ .deinit = deinit_mtrrs,
+ .core_init = NULL,
+ .core_deinit = NULL,
+ .on_entry = NULL,
+ .on_exit = NULL
+};
+
+register_extension(&mtrr_impl);
static struct v3_stream_hooks * stream_hooks = NULL;
// VM can be NULL
-v3_stream_t v3_stream_open(struct v3_vm_info * vm, const char * name) {
+struct v3_stream * v3_stream_open(struct v3_vm_info * vm, const char * name,
+ uint64_t (*input)(struct v3_stream * stream, uint8_t * buf, uint64_t len),
+ void * guest_stream_data) {
+ struct v3_stream * stream = NULL;
+
V3_ASSERT(stream_hooks != NULL);
V3_ASSERT(stream_hooks->open != NULL);
- return stream_hooks->open(name, vm->host_priv_data);
+ stream = V3_Malloc(sizeof(struct v3_stream *));
+
+ stream->input = input;
+ stream->guest_stream_data = guest_stream_data;
+ stream->host_stream_data = stream_hooks->open(stream, name, vm->host_priv_data);
+
+ return stream;
}
-int v3_stream_write(v3_stream_t stream, uint8_t * buf, uint32_t len) {
+uint64_t v3_stream_output(struct v3_stream * stream, uint8_t * buf, uint32_t len) {
V3_ASSERT(stream_hooks != NULL);
- V3_ASSERT(stream_hooks->write != NULL);
+ V3_ASSERT(stream_hooks->output != NULL);
- return stream_hooks->write(stream, buf, len);
+ return stream_hooks->output(stream, buf, len);
}
-void v3_stream_close(v3_stream_t stream) {
+void v3_stream_close(struct v3_stream * stream) {
V3_ASSERT(stream_hooks != NULL);
V3_ASSERT(stream_hooks->close != NULL);
- return stream_hooks->close(stream);
-}
-
+ stream_hooks->close(stream);
+ V3_Free(stream);
+}
vmm_xml.o \
vmm_mem_hook.o \
vmm_extensions.o \
- vmm_mtrr.o \
vmm_multitree.o \
-
+ vmm_bitmap.o \
+ vmm_barrier.o \
-
/*
* This file is part of the Palacios Virtual Machine Monitor developed
* by the V3VEE Project with funding from the United States National
#include <palacios/svm_msr.h>
#include <palacios/vmm_rbtree.h>
+#include <palacios/vmm_barrier.h>
+
#include <palacios/vmm_direct_paging.h>
int status;
// Call arch-independent handler
- if ((status = v3_handle_efer_write(core, msr, src, priv_data)) != 0)
+ if ((status = v3_handle_efer_write(core, msr, src, priv_data)) != 0) {
return status;
+ }
// SVM-specific code
- if (core->shdw_pg_mode == NESTED_PAGING) {
+ {
// Ensure that hardware visible EFER.SVME bit is set (SVM Enable)
struct efer_64 * hw_efer = (struct efer_64 *)&(core->ctrl_regs.efer);
hw_efer->svme = 1;
break;
}
+ v3_wait_at_barrier(info);
+
if (info->vm_info->run_state == VM_STOPPED) {
info->core_run_state = CORE_STOPPED;
#include <palacios/vmm_sprintf.h>
#include <palacios/vmm_xed.h>
#include <palacios/vmm_direct_paging.h>
-
+#include <palacios/vmm_barrier.h>
v3_cpu_mode_t v3_get_vm_cpu_mode(struct guest_info * info) {
v3_init_intr_routers(vm);
v3_init_ext_manager(vm);
+ v3_init_barrier(vm);
+
// Initialize the memory map
if (v3_init_mem_map(vm) == -1) {
PrintError("Could not initialize shadow map\n");
v3_deinit_intr_routers(vm);
v3_deinit_host_events(vm);
+ v3_deinit_barrier(vm);
+
v3_deinit_cpuid_map(vm);
v3_deinit_msr_map(vm);
v3_deinit_io_map(vm);
if ((os_hooks) && (os_hooks->call_on_cpu)) {
for (i = 0; i < V3_CONFIG_MAX_CPUS; i++) {
if (v3_cpu_types[i] != V3_INVALID_CPU) {
- deinit_cpu((void *)(addr_t)i);
+ V3_Call_On_CPU(i, deinit_cpu, (void *)(addr_t)i);
+ //deinit_cpu((void *)(addr_t)i);
}
}
}
}
+int v3_pause_vm(struct v3_vm_info * vm) {
+
+ if (vm->run_state != VM_RUNNING) {
+ PrintError("Tried to pause a VM that was not running\n");
+ return -1;
+ }
+
+ while (v3_raise_barrier(vm, NULL) == -1);
+
+ vm->run_state = VM_PAUSED;
+
+ return 0;
+}
+
+
+int v3_continue_vm(struct v3_vm_info * vm) {
+
+ if (vm->run_state != VM_PAUSED) {
+ PrintError("Tried to continue a VM that was not paused\n");
+ return -1;
+ }
+
+ v3_lower_barrier(vm);
+
+ vm->run_state = VM_RUNNING;
+
+ return 0;
+}
+
+
int v3_free_vm(struct v3_vm_info * vm) {
int i = 0;
// deinitialize guest (free memory, etc...)
*/
-#include <util/vmm_barrier.h>
+#include <palacios/vmm_barrier.h>
+#include <palacios/vmm.h>
+#include <palacios/vm_guest.h>
+int v3_init_barrier(struct v3_vm_info * vm_info) {
+ struct v3_barrier * barrier = &(vm_info->barrier);
-
-int v3_init_barrier(struct v3_barrier * barrier) {
memset(barrier, 0, sizeof(struct v3_barrier));
+ v3_bitmap_init(&(barrier->cpu_map), vm_info->num_cores);
v3_lock_init(&(barrier->lock));
return 0;
}
+int v3_deinit_barrier(struct v3_vm_info * vm_info) {
+ struct v3_barrier * barrier = &(vm_info->barrier);
+
+ v3_bitmap_deinit(&(barrier->cpu_map));
+ v3_lock_deinit(&(barrier->lock));
+
+ return 0;
+}
+
+
+/* Barrier synchronization primitive
+ * -- This call will block until all the guest cores are waiting at a common synchronization point
+ * in a yield loop. The core will block at the sync point until the barrier is lowered.
+ *
+ * ARGUMENTS:
+ * vm_info -- The VM for which the barrier is being activated
+ * local_core -- The core whose thread this function is being called from, or NULL
+ * if the calling thread is not associated with a VM's core context
+ */
-int v3_activate_barrier(struct guest_info * core, struct v3_barrier * barrier) {
+int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core) {
+ struct v3_barrier * barrier = &(vm_info->barrier);
addr_t flag;
int acquired = 0;
-
+ int all_blocked = 0;
+
+ int local_vcpu = -1;
+ int i = 0;
+
+
+
flag = v3_lock_irqsave(barrier->lock);
if (barrier->active == 0) {
v3_unlock_irqrestore(barrier->lock, flag);
if (acquired == 0) {
+ /* If we are in a core context and the barrier has already been acquired
+ we'll be safe and let the other barrier proceed. We will still report an error
+ though to allow possible cleanups to occur at the call site.
+ */
+ if (local_core != NULL) {
+ v3_wait_at_barrier(local_core);
+ }
+
return -1;
}
+ // If we are raising the barrier from a core context
+ // we have to mark ourselves blocked first to avoid deadlock
+ if (local_core != NULL) {
+ local_vcpu = local_core->vcpu_id;
+ v3_bitmap_set(&(barrier->cpu_map), local_vcpu);
+ }
+
- // wait for barrier catch
+ // send out interrupts to force exits on all cores
+ for (i = 0; i < vm_info->num_cores; i++) {
+ if (vm_info->cores[i].vcpu_id != local_vcpu) {
+ v3_interrupt_cpu(vm_info, vm_info->cores[i].pcpu_id, 0);
+ }
+ }
+
+ // wait for barrier catch on all cores
+ while (all_blocked == 0) {
+ all_blocked = 1;
+
+ for (i = 0; i < vm_info->num_cores; i++) {
+ if (v3_bitmap_check(&(barrier->cpu_map), i) == 0) {
+ // There is still a core that is not waiting at the barrier
+ all_blocked = 0;
+ }
+ }
+
+ if (all_blocked == 1) {
+ break;
+ }
+
+ v3_yield(local_core);
+ }
return 0;
+/* Lowers a barrier that has already been raised
+ * guest cores will automatically resume execution
+ * once this has been called
+ *
+ * TODO: Need someway to check that the barrier is active
+ */
+
+int v3_lower_barrier(struct v3_vm_info * vm_info) {
+ struct v3_barrier * barrier = &(vm_info->barrier);
+
+ // Clear the active flag, so cores won't wait
+ barrier->active = 0;
-int v3_deactivate_barrier(struct v3_barrier * barrier) {
+ // Clear all the cpu flags, so cores will proceed
+ v3_bitmap_reset(&(barrier->cpu_map));
+ return 0;
}
-int v3_check_barrier(struct guest_info * core, struct v3_barrier * barrier) {
+/*
+ * Syncronization point for guest cores
+ * -- called as part of the main VMM event loop for each core
+ * -- if a barrier has been activated then the core will signal
+ * it has reached the barrier and sit in a yield loop until the
+ * barrier has been lowered
+ */
+int v3_wait_at_barrier(struct guest_info * core) {
+ struct v3_barrier * barrier = &(core->vm_info->barrier);
- if (barrier->activated == 0) {
+ if (barrier->active == 0) {
return 0;
}
+
+ /* Barrier has been activated.
+ * Wait here until it's lowered
+ */
+
- // set cpu bit
+ // set cpu bit in barrier bitmap
+ v3_bitmap_set(&(barrier->cpu_map), core->vcpu_id);
// wait for cpu bit to clear
+ while (v3_bitmap_check(&(barrier->cpu_map), core->vcpu_id) == 1) {
+ v3_yield(core);
+ }
+ return 0;
}
--- /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) 2011, Jack Lange <jacklange@cs.pitt.edu>
+ * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * Author: Jack Lange <jacklange@cs.pitt.edu>
+ *
+ * This is free software. You are permitted to use,
+ * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
+ */
+
+#include <palacios/vmm_bitmap.h>
+#include <palacios/vmm.h>
+
+
+int v3_bitmap_init(struct v3_bitmap * bitmap, int num_bits) {
+ int num_bytes = (num_bits / 8) + ((num_bits % 8) > 0);
+
+ bitmap->num_bits = num_bits;
+ bitmap->bits = V3_Malloc(num_bytes);
+
+ if (bitmap->bits == NULL) {
+ PrintError("Could not allocate bitmap of %d bits\n", num_bits);
+ return -1;
+ }
+
+ memset(bitmap->bits, 0, num_bytes);
+
+ return 0;
+}
+
+
+void v3_bitmap_deinit(struct v3_bitmap * bitmap) {
+ V3_Free(bitmap->bits);
+}
+
+
+int v3_bitmap_reset(struct v3_bitmap * bitmap) {
+ int num_bytes = (bitmap->num_bits / 8) + ((bitmap->num_bits % 8) > 0);
+
+ memset(bitmap->bits, 0, num_bytes);
+
+ return 0;
+}
+
+int v3_bitmap_set(struct v3_bitmap * bitmap, int index) {
+ int major = index / 8;
+ int minor = index % 8;
+ int old_val = 0;
+
+ if (index > (bitmap->num_bits - 1)) {
+ PrintError("Index out of bitmap range: (pos = %d) (num_bits = %d)\n",
+ index, bitmap->num_bits);
+ return -1;
+ }
+
+ old_val = (bitmap->bits[major] & (0x1 << minor));
+ bitmap->bits[major] |= (0x1 << minor);
+
+ return old_val;
+}
+
+
+int v3_bitmap_clear(struct v3_bitmap * bitmap, int index) {
+ int major = index / 8;
+ int minor = index % 8;
+ int old_val = 0;
+
+ if (index > (bitmap->num_bits - 1)) {
+ PrintError("Index out of bitmap range: (pos = %d) (num_bits = %d)\n",
+ index, bitmap->num_bits);
+ return -1;
+ }
+
+ old_val = (bitmap->bits[major] & (0x1 << minor));
+ bitmap->bits[major] &= ~(0x1 << minor);
+
+ return old_val;
+}
+
+int v3_bitmap_check(struct v3_bitmap * bitmap, int index) {
+ int major = index / 8;
+ int minor = index % 8;
+
+ if (index > (bitmap->num_bits - 1)) {
+ PrintError("Index out of bitmap range: (pos = %d) (num_bits = %d)\n",
+ index, bitmap->num_bits);
+ return -1;
+ }
+
+ return (bitmap->bits[major] & (0x1 << minor));
+}
+
static struct hashtable * ext_table = NULL;
+/*
+ * This is a place holder to ensure that the _v3_extensions section gets created by gcc
+ */
+static struct {} null_ext __attribute__((__used__)) \
+ __attribute__((unused, __section__ ("_v3_extensions"), \
+ aligned(sizeof(addr_t))));
+
+
static uint_t ext_hash_fn(addr_t key) {
char * name = (char *)key;
// We do not support unhooking subregions
int v3_unhook_mem(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr_start) {
struct v3_mem_region * reg = v3_get_mem_region(vm, core_id, guest_addr_start);
- struct mem_hook * hook = reg->priv_data;
+ struct mem_hook * hook = NULL;
+
+ if (reg == NULL) {
+ PrintError("Could not find region at %p\n", (void *)guest_addr_start);
+ return -1;
+ }
+
+ hook = reg->priv_data;
+
+ if (hook == NULL) {
+ PrintError("Trying to unhook region that is not a hook at %p\n", (void *)guest_addr_start);
+ return -1;
+ }
+
free_hook(vm, hook);
+++ /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) 2011, Jack Lange <jarusl@cs.northwestern.edu>
- * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
- * All rights reserved.
- *
- * Author: Jack Lange <jarusl@cs.northwestern.edu>
- *
- * This is free software. You are permitted to use,
- * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
- */
-
-#include <palacios/vmm_mtrr.h>
-#include <palacios/vmm_extensions.h>
-#include <palacios/vmm.h>
-#include <palacios/vm_guest.h>
-#include <palacios/vmm_msr.h>
-
-
-#define MTRR_CAP_MSR 0x00fe
-#define MTRR_PHYS_BASE_0 0x0200
-#define MTRR_PHYS_BASE_1 0x0202
-#define MTRR_PHYS_BASE_2 0x0204
-#define MTRR_PHYS_BASE_3 0x0206
-#define MTRR_PHYS_BASE_4 0x0208
-#define MTRR_PHYS_BASE_5 0x020a
-#define MTRR_PHYS_BASE_6 0x020c
-#define MTRR_PHYS_BASE_7 0x020e
-#define MTRR_PHYS_MASK_0 0x0201
-#define MTRR_PHYS_MASK_1 0x0203
-#define MTRR_PHYS_MASK_2 0x0205
-#define MTRR_PHYS_MASK_3 0x0207
-#define MTRR_PHYS_MASK_4 0x0209
-#define MTRR_PHYS_MASK_5 0x020b
-#define MTRR_PHYS_MASK_6 0x020d
-#define MTRR_PHYS_MASK_7 0x020f
-#define MTRR_FIX_64K_00000 0x0250
-#define MTRR_FIX_16K_80000 0x0258
-#define MTRR_FIX_16K_A0000 0x0259
-#define MTRR_FIX_4K_C0000 0x0268
-#define MTRR_FIX_4K_C8000 0x0269
-#define MTRR_FIX_4K_D0000 0x026a
-#define MTRR_FIX_4K_D8000 0x026b
-#define MTRR_FIX_4K_E0000 0x026c
-#define MTRR_FIX_4K_E8000 0x026d
-#define MTRR_FIX_4K_F0000 0x026e
-#define MTRR_FIX_4K_F8000 0x026f
-
-
-struct mtrr_cap {
-
-
-};
-
-
-struct mtrr_state {
- struct mtrr_cap cap;
-
-};
-
-
-static int mtrr_cap_read(struct guest_info * core, uint32_t msr, struct v3_msr * dst, void * priv_data) {
- return 0;
-}
-
-static int mtrr_cap_write(struct guest_info * core, uint32_t msr, struct v3_msr src, void * priv_data) {
-
- return 0;
-}
-
-
-
-static int init_mtrrs(struct v3_vm_info * vm, v3_cfg_tree_t * cfg, void ** priv_data) {
-
-
- V3_Print("Intializing MTRR extension\n");
-
- v3_hook_msr(vm, MTRR_CAP_MSR, mtrr_cap_read, mtrr_cap_write, NULL);
-
-
- return 0;
-}
-
-
-static struct v3_extension_impl mtrr_ext = {
- .name = "MTRRS",
- .init = init_mtrrs,
- .deinit = NULL,
- .core_init = NULL,
- .core_deinit = NULL
-};
-
-
-
-register_extension(&mtrr_ext);
for (i = 0; i < reject_len; i++) {
if (s[cnt] == reject[i]) {
match = 1;
- cnt++;
break;
}
}
+
+ if (!match) {
+ cnt++;
+ }
+
}
return cnt;
char *str_ptr; // original xml string
char *tmp_start; // start of work area
char *tmp_end; // end of work area
- char **ent; // general entities (ampersand sequences)
- char ***attr; // default attributes
short standalone; // non-zero if <?xml standalone="yes"?>
char err[V3_XML_ERRL]; // error string
};
static char * empty_attrib_list[] = { NULL }; // empty, null terminated array of strings
+
static void * tmp_realloc(void * old_ptr, size_t old_size, size_t new_size) {
- void * new_buf = V3_Malloc(new_size);
+ void * new_buf = NULL;
+ new_buf = V3_Malloc(new_size);
+
if (new_buf == NULL) {
return NULL;
}
+ memset(new_buf, 0, new_size);
+
memcpy(new_buf, old_ptr, old_size);
V3_Free(old_ptr);
return new_buf;
}
-
-
-
-
// set an error string and return root
static void v3_xml_err(struct v3_xml_root * root, char * xml_str, const char * err, ...) {
va_list ap;
// returns the value of the requested tag attribute or NULL if not found
const char * v3_xml_attr(struct v3_xml * xml, const char * attr) {
int i = 0;
- int j = 1;
- struct v3_xml_root * root = (struct v3_xml_root *)xml;
if ((!xml) || (!xml->attr)) {
return NULL;
return xml->attr[i + 1]; // found attribute
}
- while (root->xml.parent != NULL) {
- root = (struct v3_xml_root *)root->xml.parent; // root tag
- }
-
- for (i = 0;
- ( (root->attr[i] != NULL) &&
- (strcasecmp(xml->name, root->attr[i][0]) != 0) );
- i++);
-
- if (! root->attr[i]) {
- return NULL; // no matching default attributes
- }
-
- while ((root->attr[i][j] != NULL) && (strcasecmp(attr, root->attr[i][j]) != 0)) {
- j += 3;
- }
-
- return (root->attr[i][j] != NULL) ? root->attr[i][j + 1] : NULL; // found default
+ return NULL; // found default
}
// same as v3_xml_get but takes an already initialized va_list
// for cdata sections, ' ' for attribute normalization, or '*' for non-cdata
// attribute normalization. Returns s, or if the decoded string is longer than
// s, returns a malloced string that must be freed.
-static char * v3_xml_decode(char * s, char ** ent, char t) {
+static char * v3_xml_decode(char * s, char t) {
char * e;
char * r = s;
- char * m = s;
- long b, c, d, l;
+ long c, l;
// normalize line endings
for (; *s; s++) {
*(s++) = c;
memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';')));
- } else if ( ( (*s == '&') &&
- ((t == '&') || (t == ' ') || (t == '*'))) ||
- ( (*s == '%') && (t == '%'))) {
- // entity reference`
-
- for ( (b = 0);
- (ent[b]) && (strncmp(s + 1, ent[b], strlen(ent[b])) != 0);
- (b += 2)); // find entity in entity list
-
- if (ent[b++]) { // found a match
- if (((c = strlen(ent[b])) - 1) > ((e = strchr(s, ';')) - s)) {
- l = (d = (s - r)) + c + strlen(e); // new length
- r = ((r == m) ? strcpy(V3_Malloc(l), r) : tmp_realloc(r, strlen(r), l));
- e = strchr((s = r + d), ';'); // fix up pointers
- }
-
- memmove(s + c, e + 1, strlen(e)); // shift rest of string
- strncpy(s, ent[b], c); // copy in replacement text
- } else {
- // not a known entity
- s++;
- }
} else if ( ( (t == ' ') || (t == '*')) &&
(isspace(*s))) {
*(s++) = ' ';
}
s[len] = '\0'; // null terminate text (calling functions anticipate this)
- len = strlen(s = v3_xml_decode(s, root->ent, t)) + 1;
+ len = strlen(s = v3_xml_decode(s, t)) + 1;
- if (! *(xml->txt)) {
+ if (xml->txt[0] == '\0') { // empty string
// initial character content
xml->txt = s;
} else {
+
// allocate our own memory and make a copy
- xml->txt = (xml->flags & V3_XML_TXTM) ?
- (tmp_realloc(xml->txt, strlen(xml->txt), (l = strlen(xml->txt)) + len)) :
- (strcpy(V3_Malloc((l = strlen(xml->txt)) + len), xml->txt));
+ if (xml->flags & V3_XML_TXTM) {
+ xml->txt = (tmp_realloc(xml->txt, strlen(xml->txt), (l = strlen(xml->txt)) + len));
+ } else {
+ char * tmp = NULL;
+
+ tmp = V3_Malloc((l = strlen(xml->txt)) + len);
+ strcpy(tmp, xml->txt);
+ xml->txt = tmp;
+ }
strcpy(xml->txt + l, s); // add new char content
return 0;
}
-#if 0
-// checks for circular entity references, returns non-zero if no circular
-// references are found, zero otherwise
-static int v3_xml_ent_ok(char * name, char * s, char ** ent) {
- int i;
-
- for (; ; s++) {
- while ((*s != '\0') && (*s != '&')) {
- // find next entity reference
- s++;
- }
-
- if (*s == '\0') {
- return 1;
- }
-
- if (strncmp(s + 1, name, strlen(name)) == 0) {
- // circular ref.
- return 0;
- }
-
- for (i = 0; (ent[i]) && (strncmp(ent[i], s + 1, strlen(ent[i]))); i += 2);
-
- if ((ent[i] != NULL) && (v3_xml_ent_ok(name, ent[i + 1], ent) == 0)) {
- return 0;
- }
- }
-}
-#endif
-
-
// frees a tag attribute list
static void v3_xml_free_attr(char **attr) {
m = attr[i + 1]; // list of which names and values are malloced
- for (i = 0; m[i]; i++) {
- if (m[i] & V3_XML_NAMEM) {
- V3_Free(attr[i * 2]);
- }
-
- if (m[i] & V3_XML_TXTM) {
- V3_Free(attr[(i * 2) + 1]);
- }
- }
-
V3_Free(m);
V3_Free(attr);
}
// returns a new empty v3_xml structure with the given root tag name
static struct v3_xml * v3_xml_new(const char * name) {
- static char * ent[] = { "lt;", "<", "gt;", ">", "quot;", """,
- "apos;", "'", "amp;", "&", NULL };
struct v3_xml_root * root = (struct v3_xml_root *)V3_Malloc(sizeof(struct v3_xml_root));
memset(root, 0, sizeof(struct v3_xml_root));
root->xml.txt = "";
memset(root->err, 0, V3_XML_ERRL);
- root->ent = V3_Malloc(sizeof(ent));
- memcpy(root->ent, ent, sizeof(ent));
-
- root->xml.attr = empty_attrib_list;
- root->attr = (char ***)(empty_attrib_list);
return &root->xml;
}
char last_char;
char * tag_ptr;
char ** attr;
- char ** tmp_attr = NULL; // initialize a to avoid compile warning
int attr_idx;
- int i, j;
root->str_ptr = buf;
*(buf++) = '\0';
}
- // check if attribute follows tag
- if ((*buf) && (*buf != '/') && (*buf != '>')) {
- // there is an attribute
- // find attributes for correct tag
- for ((i = 0);
- ((tmp_attr = root->attr[i]) &&
- (strcasecmp(tmp_attr[0], tag_ptr) != 0));
- (i++)) ;
-
- // 'tmp_attr' now points to the attribute list associated with 'tag_ptr'
- }
+
// attributes are name value pairs,
// 2nd to last entry is null (end of list)
(2 * sizeof(char *))),
((attr_cnt * (2 * sizeof(char *))) +
(2 * sizeof(char *))));
-
+
attr[last_idx] = tmp_realloc(attr[last_idx - 2],
attr_cnt,
(attr_cnt + 1));
attr = V3_Malloc(4 * sizeof(char *));
attr[last_idx] = V3_Malloc(2);
}
-
attr[attr_idx] = buf; // set attribute name
attr[val_idx] = ""; // temporary attribute value
buf += strcspn(buf, V3_XML_WS "=/>");
if ((*buf == '=') || isspace(*buf)) {
-
+
*(buf++) = '\0'; // null terminate tag attribute name
-
+
// eat whitespace (and more multiple '=' ?)
buf += strspn(buf, V3_XML_WS "=");
return NULL;
}
- for (j = 1;
- ( (tmp_attr) && (tmp_attr[j]) &&
- (strcasecmp(tmp_attr[j], attr[attr_idx]) != 0));
- j += 3);
-
- attr[val_idx] = v3_xml_decode(attr[val_idx], root->ent,
- ((tmp_attr && tmp_attr[j]) ?
- *tmp_attr[j + 2] :
- ' '));
-
- if ( (attr[val_idx] < tag_ptr) ||
- (attr[val_idx] > buf) ) {
- attr[last_idx][attr_cnt - 1] = V3_XML_TXTM; // value malloced
- }
+ attr[val_idx] = v3_xml_decode(attr[val_idx], ' ');
}
}
*buf = '\0';
tag_ptr = ++buf;
+ /* Eat leading whitespace */
+ while (*buf && isspace(*buf)) {
+ buf++;
+ }
+
if (*buf && (*buf != '<')) {
// tag character content
while (*buf && (*buf != '<')) {
// free the memory allocated for the v3_xml structure
void v3_xml_free(struct v3_xml * xml) {
struct v3_xml_root * root = (struct v3_xml_root *)xml;
- int i, j;
- char **a, *s;
if (xml == NULL) {
return;
if (xml->parent == NULL) {
// free root tag allocations
-
- for (i = 10; root->ent[i]; i += 2) {
- // 0 - 9 are default entites (<>&"')
- if ((s = root->ent[i + 1]) < root->tmp_start || s > root->tmp_end) {
- V3_Free(s);
- }
- }
-
- V3_Free(root->ent); // free list of general entities
-
- for (i = 0; (a = root->attr[i]); i++) {
- for (j = 1; a[j++]; j += 2) {
- // free malloced attribute values
- if (a[j] && (a[j] < root->tmp_start || a[j] > root->tmp_end)) {
- V3_Free(a[j]);
- }
- }
- V3_Free(a);
- }
-
- if (root->attr[0]) {
- // free default attribute list
- V3_Free(root->attr);
- }
-
V3_Free(root->str_ptr); // malloced xml data
}
v3_xml_free_attr(xml->attr); // tag attributes
+
+
if ((xml->flags & V3_XML_TXTM)) {
// character content
V3_Free(xml->txt);
+/* Adding XML data */
+
+
// sets the character content for the given tag and returns the tag
// its length excedes max. start is the location of the previous tag in the
// parent tag's character content. Returns *s.
static char *toxml_r(struct v3_xml * xml, char **s, size_t *len, size_t *max,
- size_t start, char ***attr) {
- int i, j;
+ size_t start) {
+ int i;
char *txt = (xml->parent) ? xml->parent->txt : "";
size_t off = 0;
*len += sprintf(*s + *len, "\"");
}
- for (i = 0; attr[i] && strcmp(attr[i][0], xml->name); i++);
- for (j = 1; attr[i] && attr[i][j]; j += 3) { // default attributes
- if (! attr[i][j + 1] || v3_xml_attr(xml, attr[i][j]) != attr[i][j + 1])
- continue; // skip duplicates and non-values
- while (*len + strlen(attr[i][j]) + 7 > *max) {
- // reallocate s
- *s = tmp_realloc(*s, *max, *max + V3_XML_BUFSIZE);
- *max += V3_XML_BUFSIZE;
- }
-
- *len += sprintf(*s + *len, " %s=\"", attr[i][j]);
- ampencode(attr[i][j + 1], -1, s, len, max, 1);
- *len += sprintf(*s + *len, "\"");
- }
+
*len += sprintf(*s + *len, ">");
- *s = (xml->child) ? toxml_r(xml->child, s, len, max, 0, attr) //child
+ *s = (xml->child) ? toxml_r(xml->child, s, len, max, 0) //child
: ampencode(xml->txt, -1, s, len, max, 0); //data
while (*len + strlen(xml->name) + 4 > *max) {
*len += sprintf(*s + *len, "</%s>", xml->name); // close tag
while (txt[off] && off < xml->off) off++; // make sure off is within bounds
- return (xml->ordered) ? toxml_r(xml->ordered, s, len, max, off, attr)
+ return (xml->ordered) ? toxml_r(xml->ordered, s, len, max, off)
: ampencode(txt + off, -1, s, len, max, 0);
}
xml->parent = xml->ordered = NULL;
- s = toxml_r(xml, &s, &len, &max, 0, root->attr);
+ s = toxml_r(xml, &s, &len, &max, 0);
xml->parent = p;
xml->ordered = o;
struct vmx_data * vmx_state = core->vmm_data;
V3_FreePages((void *)(vmx_state->vmcs_ptr_phys), 1);
- V3_FreePages(vmx_state->msr_area, 1);
+ V3_FreePages(V3_PAddr(vmx_state->msr_area), 1);
V3_Free(vmx_state);
void v3_init_vmx_cpu(int cpu_id) {
+ addr_t vmx_on_region = 0;
if (cpu_id == 0) {
if (v3_init_vmx_hw(&hw_info) == -1) {
// Setup VMXON Region
- host_vmcs_ptrs[cpu_id] = allocate_vmcs();
+ vmx_on_region = allocate_vmcs();
- PrintDebug("VMXON pointer: 0x%p\n", (void *)host_vmcs_ptrs[cpu_id]);
- if (vmx_on(host_vmcs_ptrs[cpu_id]) == VMX_SUCCESS) {
+ if (vmx_on(vmx_on_region) == VMX_SUCCESS) {
V3_Print("VMX Enabled\n");
+ host_vmcs_ptrs[cpu_id] = vmx_on_region;
} else {
- PrintError("VMX initialization failure\n");
- return;
+ V3_Print("VMX already enabled\n");
+ V3_FreePages((void *)vmx_on_region, 1);
}
-
+
+ PrintDebug("VMXON pointer: 0x%p\n", (void *)host_vmcs_ptrs[cpu_id]);
{
struct vmx_sec_proc_ctrls sec_proc_ctrls;
void v3_deinit_vmx_cpu(int cpu_id) {
extern v3_cpu_arch_t v3_cpu_types[];
v3_cpu_types[cpu_id] = V3_INVALID_CPU;
- V3_FreePages((void *)host_vmcs_ptrs[cpu_id], 1);
+
+ if (host_vmcs_ptrs[cpu_id] != 0) {
+ V3_Print("Disabling VMX\n");
+
+ if (vmx_off() != VMX_SUCCESS) {
+ PrintError("Error executing VMXOFF\n");
+ }
+
+ V3_FreePages((void *)host_vmcs_ptrs[cpu_id], 1);
+
+ host_vmcs_ptrs[cpu_id] = 0;
+ }
}
PrintError("Page fault in unimplemented paging mode\n");
return -1;
}
+ } else if ((uint8_t)exit_info->int_info == 2) {
+ // NMI. Don't do anything
+ V3_Print("NMI Exception Received\n");
} else {
PrintError("Unknown exception: 0x%x\n", (uint8_t)exit_info->int_info);
v3_print_GPRs(info);
* Copyright (c) 2010, Lei Xia <lxia@northwestern.edu>
* Copyright (c) 2009, Yuan Tang <ytang@northwestern.edu>
* Copyright (c) 2009, The V3VEE Project <http://www.v3vee.org>
- * All rights reserved.
+ * All rights reserved
*
* Author: Lei Xia <lxia@northwestern.edu>
* Yuan Tang <ytang@northwestern.edu>
#include <vnet/vnet_host.h>
#include <vnet/vnet_vmm.h>
+#include <palacios/vmm_queue.h>
+
#ifndef V3_CONFIG_DEBUG_VNET
#undef Vnet_Debug
#define Vnet_Debug(fmt, args...)
uint8_t mac_addr[ETH_ALEN];
struct v3_vm_info * vm;
struct v3_vnet_dev_ops dev_ops;
+
+ int poll;
+
+#define VNET_MAX_QUOTE 64
+ int quote;
+
void * private_data;
- struct list_head node;
+ struct list_head node;\r
} __attribute__((packed));
uint32_t size_alloc;
};
-#define VNET_QUEUE_SIZE 1024
-struct vnet_queue {
- struct queue_entry buf[VNET_QUEUE_SIZE];
- int head, tail;
- int count;
- vnet_lock_t lock;
-};
static struct {
struct list_head routes;
vnet_lock_t lock;
struct vnet_stat stats;
- struct vnet_thread * pkt_flush_thread;
+ /* device queue that are waiting to be polled */
+ struct v3_queue * poll_devs;
- struct vnet_queue pkt_q;
+ struct vnet_thread * pkt_flush_thread;
struct hashtable * route_cache;
} vnet_state;
}
-int vnet_tx_one_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
+int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data) {
struct route_list * matched_routes = NULL;
unsigned long flags;
int i;
int cpu = V3_Get_CPU();
Vnet_Print(2, "VNET/P Core: cpu %d: pkt (size %d, src_id:%d, src_type: %d, dst_id: %d, dst_type: %d)\n",
- cpu, pkt->size, pkt->src_id,
- pkt->src_type, pkt->dst_id, pkt->dst_type);
+ cpu, pkt->size, pkt->src_id,
+ pkt->src_type, pkt->dst_id, pkt->dst_type);
if(net_debug >= 4){
- v3_hexdump(pkt->data, pkt->size, NULL, 0);
+ v3_hexdump(pkt->data, pkt->size, NULL, 0);
}
flags = vnet_lock_irqsave(vnet_state.lock);
}
-static int vnet_pkt_enqueue(struct v3_vnet_pkt * pkt){
- unsigned long flags;
- struct queue_entry * entry;
- struct vnet_queue * q = &(vnet_state.pkt_q);
- uint16_t num_pages;
-
- flags = vnet_lock_irqsave(q->lock);
-
- if (q->count >= VNET_QUEUE_SIZE){
- Vnet_Print(1, "VNET Queue overflow!\n");
- vnet_unlock_irqrestore(q->lock, flags);
- return -1;
- }
-
- q->count ++;
- entry = &(q->buf[q->tail++]);
- q->tail %= VNET_QUEUE_SIZE;
-
- vnet_unlock_irqrestore(q->lock, flags);
-
- /* this is ugly, but should happen very unlikely */
- while(entry->use);
-
- if(entry->size_alloc < pkt->size){
- if(entry->data != NULL){
- Vnet_FreePages(Vnet_PAddr(entry->data), (entry->size_alloc / PAGE_SIZE));
- entry->data = NULL;
- }
-
- num_pages = 1 + (pkt->size / PAGE_SIZE);
- entry->data = Vnet_VAddr(Vnet_AllocPages(num_pages));
- if(entry->data == NULL){
- return -1;
- }
- entry->size_alloc = PAGE_SIZE * num_pages;
- }
-
- entry->pkt.data = entry->data;
- memcpy(&(entry->pkt), pkt, sizeof(struct v3_vnet_pkt));
- memcpy(entry->data, pkt->data, pkt->size);
-
- entry->use = 1;
-
- return 0;
-}
-
-
-int v3_vnet_send_pkt(struct v3_vnet_pkt * pkt, void * private_data, int synchronize) {
- if(synchronize){
- vnet_tx_one_pkt(pkt, NULL);
- }else {
- vnet_pkt_enqueue(pkt);
- Vnet_Print(2, "VNET/P Core: Put pkt into Queue: pkt size %d\n", pkt->size);
- }
-
- return 0;
-}
-
int v3_vnet_add_dev(struct v3_vm_info * vm, uint8_t * mac,
- struct v3_vnet_dev_ops *ops,
+ struct v3_vnet_dev_ops *ops, int quote, int poll_state,
void * priv_data){
struct vnet_dev * new_dev = NULL;
unsigned long flags;
new_dev->private_data = priv_data;
new_dev->vm = vm;
new_dev->dev_id = 0;
+ new_dev->quote = quote<VNET_MAX_QUOTE?quote:VNET_MAX_QUOTE;
+ new_dev->poll = poll_state;
flags = vnet_lock_irqsave(vnet_state.lock);
}
+/* can be instanieoued to multiple threads
+ * that runs on multiple cores
+ * or it could be running on a dedicated side core
+ */
static int vnet_tx_flush(void *args){
- unsigned long flags;
- struct queue_entry * entry;
- struct vnet_queue * q = &(vnet_state.pkt_q);
+ struct vnet_dev * dev = NULL;
+ int ret;
- Vnet_Print(0, "VNET/P Handing Pkt Thread Starting ....\n");
+ Vnet_Print(0, "VNET/P Polling Thread Starting ....\n");
/* we need thread sleep/wakeup in Palacios */
while(!vnet_thread_should_stop()){
- flags = vnet_lock_irqsave(q->lock);
-
- if (q->count <= 0){
- vnet_unlock_irqrestore(q->lock, flags);
- Vnet_Yield();
- }else {
- q->count --;
- entry = &(q->buf[q->head++]);
- q->head %= VNET_QUEUE_SIZE;
-
- vnet_unlock_irqrestore(q->lock, flags);
+ dev = (struct vnet_dev *)v3_dequeue(vnet_state.poll_devs);
+ if(dev != NULL){
+ if(dev->poll && dev->dev_ops.poll != NULL){
+ ret = dev->dev_ops.poll(dev->vm, dev->quote, dev->private_data);
- /* this is ugly, but should happen very unlikely */
- while(!entry->use);
- vnet_tx_one_pkt(&(entry->pkt), NULL);
-
- /* asynchronizely release allocated memory for buffer entry here */
- entry->use = 0;
+ if (ret < 0){
+ PrintDebug("VNET/P: poll from device %p error!\n", dev);
+ }
- Vnet_Print(2, "vnet_tx_flush: pkt (size %d)\n", entry->pkt.size);
+ v3_enqueue(vnet_state.poll_devs, (addr_t)dev);
+ }
+ }else { /* no device needs to be polled */
+ /* sleep here? */
+ Vnet_Yield();
}
}
return 0;
}
+
int v3_init_vnet() {
memset(&vnet_state, 0, sizeof(vnet_state));
vnet_state.num_routes = 0;
if (vnet_lock_init(&(vnet_state.lock)) == -1){
- PrintError("VNET/P Core: Fails to initiate lock\n");
+ PrintError("VNET/P: Fails to initiate lock\n");
}
vnet_state.route_cache = vnet_create_htable(0, &hash_fn, &hash_eq);
if (vnet_state.route_cache == NULL) {
- PrintError("VNET/P Core: Fails to initiate route cache\n");
+ PrintError("VNET/P: Fails to initiate route cache\n");
return -1;
}
- vnet_lock_init(&(vnet_state.pkt_q.lock));
+ vnet_state.poll_devs = v3_create_queue();
- vnet_state.pkt_flush_thread = vnet_start_thread(vnet_tx_flush, NULL, "VNET_Pkts");
+ vnet_state.pkt_flush_thread = vnet_start_thread(vnet_tx_flush, NULL, "vnetd");
- Vnet_Debug("VNET/P Core is initiated\n");
+ Vnet_Debug("VNET/P is initiated\n");
return 0;
}