EXTRA_CFLAGS += -I$(PWD)/../palacios/include/ -include autoconf.h -DMODULE=1 -D__KERNEL__=1
-v3vee-objs := palacios.o \
+v3vee-y := palacios.o \
palacios-dev.o \
palacios-vm.o \
palacios-mm.o \
palacios-queue.o \
- palacios-hashtable.o
+ palacios-hashtable.o \
+ linux-exts.o
-ifdef V3_CONFIG_CONSOLE
- v3vee-objs += palacios-console.o
-endif
-
-ifdef V3_CONFIG_FILE
- v3vee-objs += palacios-file.o
-endif
-
-ifdef V3_CONFIG_STREAM
- v3vee-objs += palacios-stream.o \
- palacios-ringbuffer.o
-endif
-
-ifdef V3_CONFIG_EXT_INSPECTOR
- v3vee-objs += palacios-inspector.o
-endif
-
-ifdef V3_CONFIG_VNET
- v3vee-objs += palacios-vnet.o \
- palacios-vnet-ctrl.o \
- palacios-vnet-brg.o
-endif
+v3vee-$(V3_CONFIG_CONSOLE) += palacios-console.o
+v3vee-$(V3_CONFIG_FILE) += palacios-file.o
+v3vee-$(V3_CONFIG_STREAM) += palacios-stream.o \
+ palacios-ringbuffer.o
+v3vee-$(V3_CONFIG_EXT_INSPECTOR) += palacios-inspector.o
+v3vee-$(V3_CONFIG_PACKET) += palacios-packet.o
+v3vee-$(V3_CONFIG_SOCKET) += palacios-socket.o
+v3vee-$(V3_CONFIG_KEYED_STREAMS) += palacios-keyed-stream.o
+v3vee-$(V3_CONFIG_HOST_DEVICE) += palacios-host-dev.o
+v3vee-$(V3_CONFIG_GRAPHICS_CONSOLE) += palacios-graphics-console.o
-ifdef V3_CONFIG_PACKET
- v3vee-objs += palacios-packet.o
-endif
-
-ifdef V3_CONFIG_SOCKET
- v3vee-objs += palacios-socket.o
-endif
-
-ifdef V3_CONFIG_KEYED_STREAMS
- v3vee-objs += palacios-keyed-stream.o
-endif
-
-ifdef V3_CONFIG_HOST_DEVICE
- v3vee-objs += palacios-host-dev.o
-endif
-
-ifdef V3_CONFIG_GRAPHICS_CONSOLE
- v3vee-objs += palacios-graphics-console.o
-endif
+v3vee-$(V3_CONFIG_VNET) += palacios-vnet.o \
+ palacios-vnet-ctrl.o \
+ palacios-vnet-brg.o
-v3vee-objs += ../libv3vee.a
+v3vee-objs := $(v3vee-y) ../libv3vee.a
obj-m := v3vee.o
SECTIONS
{
+
+ _lnx_exts :
+ {
+ __start__lnx_exts = .;
+ *(_lnx_exts);
+ __stop__lnx_exts = .;
+ }
_v3_devices :
{
__start__v3_devices = .;
__stop__v3_extensions = .;
}
+
}
--- /dev/null
+
+#include "linux-exts.h"
+
+/*
+ * This is a place holder to ensure that the _lnx_exts section gets created by gcc
+ */
+
+
+static struct {} null_ext __attribute__((__used__)) \
+ __attribute__((unused, __section__ ("_lnx_exts"), \
+ aligned(sizeof(void *))));
+
+struct vm_ext {
+ struct linux_ext * impl;
+ void * vm_data;
+ struct list_head node;
+};
+
+
+void * get_vm_ext_data(struct v3_guest * guest, char * ext_name) {
+ struct vm_ext * ext = NULL;
+
+ list_for_each_entry(ext, &(guest->exts), node) {
+ if (strncmp(ext->impl->name, ext_name, strlen(ext->impl->name)) == 0) {
+ return ext->vm_data;
+ }
+ }
+
+ return NULL;
+}
+
+
+int init_vm_extensions(struct v3_guest * guest) {
+ extern struct linux_ext * __start__lnx_exts[];
+ extern struct linux_ext * __stop__lnx_exts[];
+ struct linux_ext * ext_impl = __start__lnx_exts[0];
+ int i = 0;
+
+ while (ext_impl != __stop__lnx_exts[0]) {
+ struct vm_ext * ext = NULL;
+
+ if (ext_impl->guest_init == NULL) {
+ // We can have global extensions without per guest state
+ ext_impl = __start__lnx_exts[++i];
+ continue;
+ }
+
+ printk("Registering Linux Extension (%s)\n", ext_impl->name);
+
+ ext = kmalloc(sizeof(struct vm_ext), GFP_KERNEL);
+
+ if (!ext) {
+ printk("Error allocating VM extension (%s)\n", ext_impl->name);
+ return -1;
+ }
+
+ ext->impl = ext_impl;
+
+ ext_impl->guest_init(guest, &(ext->vm_data));
+
+ list_add(&(ext->node), &(guest->exts));
+
+ ext_impl = __start__lnx_exts[++i];
+ }
+
+ return 0;
+}
+
+
+
+int deinit_vm_extensions(struct v3_guest * guest) {
+ struct vm_ext * ext = NULL;
+ struct vm_ext * tmp = NULL;
+
+ list_for_each_entry_safe(ext, tmp, &(guest->exts), node) {
+ if (ext->impl->guest_deinit) {
+ ext->impl->guest_deinit(guest, ext->vm_data);
+ } else {
+ printk("WARNING: Extension %s, does not have a guest deinit function\n", ext->impl->name);
+ }
+
+ list_del(&(ext->node));
+ kfree(ext);
+ }
+
+ return 0;
+}
+
+int init_lnx_extensions( void ) {
+ extern struct linux_ext * __start__lnx_exts[];
+ extern struct linux_ext * __stop__lnx_exts[];
+ struct linux_ext * tmp_ext = __start__lnx_exts[0];
+ int i = 0;
+
+ while (tmp_ext != __stop__lnx_exts[0]) {
+
+ printk("tmp_ext=%p\n", tmp_ext);
+
+ if (tmp_ext->init != NULL) {
+ printk("Registering Linux Extension (%s)\n", tmp_ext->name);
+ tmp_ext->init();
+ }
+
+ tmp_ext = __start__lnx_exts[++i];
+ }
+
+ return 0;
+}
+
+
+int deinit_lnx_extensions( void ) {
+ extern struct linux_ext * __start__lnx_exts[];
+ extern struct linux_ext * __stop__lnx_exts[];
+ struct linux_ext * tmp_ext = __start__lnx_exts[0];
+ int i = 0;
+
+ while (tmp_ext != __stop__lnx_exts[0]) {
+ printk("Cleaning up Linux Extension (%s)\n", tmp_ext->name);
+ if (tmp_ext->deinit != NULL) {
+ tmp_ext->deinit();
+ } else {
+ printk("WARNING: Extension %s does not have a global deinit function\n", tmp_ext->name);
+ }
+
+ tmp_ext = __start__lnx_exts[++i];
+ }
+
+ return 0;
+}
--- /dev/null
+#include "palacios.h"
+
+
+int add_mod_cmd(struct v3_guest * guest, unsigned int cmd,
+ int (*handler)(struct v3_guest * guest,
+ unsigned int cmd, unsigned long arg));
+
+
+struct linux_ext {
+ char * name;
+ int (*init)( void );
+ int (*deinit)( void );
+ int (*guest_init)(struct v3_guest * guest, void ** priv_data);
+ int (*guest_deinit)(struct v3_guest * guest, void * priv_data);
+};
+
+
+
+int init_lnx_extensions( void );
+int deinit_lnx_extensions( void );
+
+int init_vm_extensions(struct v3_guest * guest);
+int deinit_vm_extensions(struct v3_guest * guest);
+
+void * get_vm_ext_data(struct v3_guest * guest, char * ext_name);
+
+
+
+#define register_extension(ext) \
+ static struct linux_ext * _lnx_ext \
+ __attribute__((used)) \
+ __attribute__((unused, __section__("_lnx_exts"), \
+ aligned(sizeof(void *)))) \
+ = ext;
#include <interfaces/vmm_console.h>
#include <palacios/vmm_host_events.h>
+#include "palacios-vm.h"
#include "palacios.h"
-#include "palacios-console.h"
#include "palacios-queue.h"
+#include "linux-exts.h"
typedef enum { CONSOLE_CURS_SET = 1,
CONSOLE_CHAR_SET = 2,
+struct palacios_console {
+ struct gen_queue * queue;
+ spinlock_t lock;
+
+ int open;
+ int connected;
+
+ wait_queue_head_t intr_queue;
+
+ unsigned int width;
+ unsigned int height;
+
+ struct v3_guest * guest;
+};
+
+
+
struct cursor_msg {
int x;
int y;
-int connect_console(struct v3_guest * guest) {
- struct palacios_console * cons = &(guest->console);
+static int console_connect(struct v3_guest * guest, unsigned int cmd,
+ unsigned long arg, void * priv_data) {
+ struct palacios_console * cons = priv_data;
int cons_fd = 0;
unsigned long flags;
static void * palacios_tty_open(void * private_data, unsigned int width, unsigned int height) {
struct v3_guest * guest = (struct v3_guest *)private_data;
- struct palacios_console * cons = &(guest->console);
+ struct palacios_console * cons = kmalloc(sizeof(struct palacios_console), GFP_KERNEL);
printk("Guest initialized virtual console (Guest=%s)\n", guest->name);
}
- cons->width = width;
- cons->height = height;
-
cons->queue = create_queue(CONSOLE_QUEUE_LEN);
spin_lock_init(&(cons->lock));
init_waitqueue_head(&(cons->intr_queue));
cons->guest = guest;
- cons->open = 1;
cons->connected = 0;
+ cons->width = width;
+ cons->height = height;
+ cons->open = 1;
+ add_guest_ctrl(guest, V3_VM_CONSOLE_CONNECT, console_connect, cons);
+
return cons;
}
-int palacios_init_console( void ) {
+
+
+
+static int console_init( void ) {
V3_Init_Console(&palacios_console_hooks);
return 0;
}
+
+
+
+
+static struct linux_ext console_ext = {
+ .name = "CONSOLE",
+ .init = console_init,
+ .deinit = NULL,
+ .guest_init = NULL,
+ .guest_deinit = NULL
+};
+
+
+register_extension(&console_ext);
+++ /dev/null
-/*
- * Palacios VM Stream Console interface
- * (c) Jack Lange, 2010
- */
-
-#ifndef __PALACIOS_CONSOLE_H__
-#define __PALACIOS_CONSOLE_H__
-
-
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-
-
-struct palacios_console {
- struct gen_queue * queue;
- spinlock_t lock;
-
- int open;
- int connected;
-
- wait_queue_head_t intr_queue;
-
- unsigned int width;
- unsigned int height;
-
- struct v3_guest * guest;
-};
-
-
-
-struct v3_guest;
-
-
-int connect_console(struct v3_guest * guest);
-
-int palacios_init_console( void );
-
-
-#endif
#include "palacios.h"
#include "palacios-mm.h"
#include "palacios-vm.h"
-#include "palacios-stream.h"
-#include "palacios-file.h"
-#include "palacios-serial.h"
-#include "palacios-socket.h"
-#include "palacios-vnet.h"
-#include "palacios-packet.h"
-#ifdef V3_CONFIG_EXT_INSPECTOR
-#include "palacios-inspector.h"
-#endif
+#include "linux-exts.h"
-#ifdef V3_CONFIG_KEYED_STREAMS
-#include "palacios-keyed-stream.h"
-#endif
MODULE_LICENSE("GPL");
struct class * v3_class = NULL;
static struct cdev ctrl_dev;
-void * v3_base_addr = NULL;
-unsigned int v3_pages = 0;
-
static int register_vm( void ) {
int i, j = 0;
int avail = 0;
printk("Launching VM\n");
- INIT_LIST_HEAD(&(guest->streams));
- INIT_LIST_HEAD(&(guest->files));
- INIT_LIST_HEAD(&(guest->sockets));
-#ifdef V3_CONFIG_HOST_DEVICE
- INIT_LIST_HEAD(&(guest->hostdev.devs));
-#endif
+ INIT_LIST_HEAD(&(guest->exts));
+
init_completion(&(guest->start_done));
init_completion(&(guest->thread_done));
};
-extern unsigned int v3_pages;
-extern void * v3_base_addr;
static int __init v3_init(void) {
dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
palacios_init_mm();
+
+ // Initialize Palacios
+
+ palacios_vmm_init();
+
+
+ // initialize extensions
+ init_lnx_extensions();
+
+
v3_class = class_create(THIS_MODULE, "vms");
if (IS_ERR(v3_class)) {
printk("Failed to register V3 VM device class\n");
goto failure1;
}
- if ((v3_pages > 0) && (v3_base_addr != NULL)) {
- add_palacios_memory(__pa(v3_base_addr), v3_pages);
- }
-
- // Initialize Palacios
-
- palacios_vmm_init();
-
-#ifdef V3_CONFIG_STREAM
- palacios_init_stream();
-#endif
-
-#ifdef V3_CONFIG_FILE
- palacios_file_init();
-#endif
-
-#ifdef V3_CONFIG_KEYED_STREAMS
- palacios_init_keyed_streams();
-#endif
-
-#ifdef V3_CONFIG_CONSOLE
- palacios_init_console();
-#endif
-
-#ifdef V3_CONFIG_GRAPHICS_CONSOLE
- palacios_init_graphics_console();
-#endif
-
-#ifdef V3_CONFIG_EXT_INSPECTOR
- palacios_init_inspector();
-#endif
-
-#ifdef V3_CONFIG_SOCKET
- palacios_socket_init();
-#endif
-
-#ifdef V3_CONFIG_PACKET
- palacios_init_packet(NULL);
-#endif
-#ifdef V3_CONFIG_VNET
- palacios_vnet_init();
-#endif
-
-#ifdef V3_CONFIG_HOST_DEVICE
- palacios_init_host_dev();
-#endif
return 0;
class_destroy(v3_class);
-
-#ifdef V3_CONFIG_EXT_INSPECTOR
- palacios_deinit_inspector();
-#endif
-
-#ifdef V3_CONFIG_FILE
- palacios_file_deinit();
-#endif
-
-#ifdef V3_CONFIG_STREAM
- palacios_deinit_stream();
-#endif
-
-#ifdef V3_CONFIG_SOCKET
- palacios_socket_deinit();
-#endif
-
-#ifdef V3_CONFIG_PACKET
- palacios_deinit_packet(NULL);
-#endif
-
-#ifdef V3_CONFIG_VNET
- palacios_vnet_deinit();
-#endif
+ deinit_lnx_extensions();
palacios_deinit_mm();
#include <linux/module.h>
#include "palacios.h"
+#include "linux-exts.h"
#include <interfaces/vmm_file.h>
static struct list_head global_files;
+
struct palacios_file {
struct file * filp;
};
+// Currently this just holds the list of open files
+struct vm_file_state {
+ struct list_head open_files;
+};
+
+
static void * palacios_file_open(const char * path, int mode, void * private_data) {
struct v3_guest * guest = (struct v3_guest *)private_data;
- struct palacios_file * pfile = NULL;
+ struct palacios_file * pfile = NULL;
+ struct vm_file_state * vm_state = NULL;
+
+ if (guest != NULL) {
+ vm_state = get_vm_ext_data(guest, "FILE_INTERFACE");
+
+ if (vm_state == NULL) {
+ printk("ERROR: Could not locate vm file state for extension FILE_INTERFACE\n");
+ return NULL;
+ }
+ }
pfile = kmalloc(sizeof(struct palacios_file), GFP_KERNEL);
memset(pfile, 0, sizeof(struct palacios_file));
if (guest == NULL) {
list_add(&(pfile->file_node), &(global_files));
} else {
- list_add(&(pfile->file_node), &(guest->files));
+ list_add(&(pfile->file_node), &(vm_state->open_files));
}
};
-int palacios_file_init( void ) {
+
+static int file_init( void ) {
INIT_LIST_HEAD(&(global_files));
V3_Init_File(&palacios_file_hooks);
}
-int palacios_file_deinit( void ) {
+static int file_deinit( void ) {
if (!list_empty(&(global_files))) {
printk("Error removing module with open files\n");
}
return 0;
}
+
+static int guest_file_init(struct v3_guest * guest, void ** vm_data) {
+ struct vm_file_state * state = kmalloc(sizeof(struct vm_file_state), GFP_KERNEL);
+
+ INIT_LIST_HEAD(&(state->open_files));
+
+ *vm_data = state;
+
+ return 0;
+}
+
+
+static int guest_file_deinit(struct v3_guest * guest, void * vm_data) {
+
+ return 0;
+}
+
+
+static struct linux_ext file_ext = {
+ .name = "FILE_INTERFACE",
+ .init = file_init,
+ .deinit = file_deinit,
+ .guest_init = guest_file_init,
+ .guest_deinit = guest_file_deinit
+};
+
+
+register_extension(&file_ext);
+++ /dev/null
-#ifndef __PALACIOS_FILE_H__
-#define __PALACISO_FILE_H__
-
-int palacios_file_init(void);
-int palacios_file_deinit(void);
-
-#endif
#include <interfaces/vmm_console.h>
#include <palacios/vmm_host_events.h>
+#include "palacios-graphics-console.h"
+
#include "palacios.h"
-#include "palacios-graphics-console.h"
+#include "linux-exts.h"
+#include "palacios-vm.h"
#include <linux/vmalloc.h>
*/
+
+
+struct palacios_graphics_console {
+ // descriptor for the data in the shared frame buffer
+ struct v3_frame_buffer_spec spec;
+
+ // the actual shared frame buffer
+ // Note that "shared" here means shared between palacios and us
+ // This data could of course also be shared with userland
+ void * data;
+
+ int cons_refcount;
+ int data_refcount;
+
+ uint32_t num_updates;
+
+ // Currently keystrokes and mouse movements are ignored
+
+ // currently, we will not worry about locking this
+ // lock_t ...
+};
+
+
static v3_graphics_console_t g_open(void * priv_data,
struct v3_frame_buffer_spec *desired_spec,
struct v3_frame_buffer_spec *actual_spec)
{
struct v3_guest * guest = (struct v3_guest *)priv_data;
- struct palacios_graphics_console *gc = (struct palacios_graphics_console *) &(guest->graphics_console);
+ struct palacios_graphics_console * gc = NULL;
uint32_t mem;
- if(gc->data) {
+ if (guest == NULL) {
+ return 0;
+ }
+
+ gc = get_vm_ext_data(guest, "GRAPHICS_CONSOLE_INTERFACE");
+
+ if (gc == NULL) {
+ printk("palacios: Could not locate graphics console data for extension GRAPHICS_CONSOLE_INTERFACE\n");
+ return 0;
+ }
+
+ if (gc->data != NULL) {
printk("palacios: framebuffer already allocated - returning it\n");
- *actual_spec=gc->spec;
+
+ *actual_spec = gc->spec;
gc->cons_refcount++;
gc->data_refcount++;
+
return gc;
}
*actual_spec = gc->spec;
- gc->guest=guest;
gc->cons_refcount++;
gc->data_refcount++;
gc->cons_refcount--;
gc->data_refcount--;
- if (gc->data_refcount<gc->cons_refcount) {
+ if (gc->data_refcount < gc->cons_refcount) {
printk("palacios: error! data refcount is less than console refcount for graphics console\n");
}
- if (gc->cons_refcount>0) {
+ if (gc->cons_refcount > 0) {
return;
} else {
- if (gc->cons_refcount<0) {
+ if (gc->cons_refcount < 0) {
printk("palacios: error! refcount for graphics console is negative on close!\n");
}
- if (gc->data_refcount>0) {
+ if (gc->data_refcount > 0) {
printk("palacios: error! refcount for graphics console data is positive on close - LEAKING MEMORY\n");
return;
}
-static int palacios_graphics_console_key(struct palacios_graphics_console *cons, uint8_t scancode)
+static int palacios_graphics_console_key(struct v3_guest * guest,
+ struct palacios_graphics_console *cons,
+ uint8_t scancode)
{
struct v3_keyboard_event e;
- e.status=0;
- e.scan_code=scancode;
+ e.status = 0;
+ e.scan_code = scancode;
- v3_deliver_keyboard_event(cons->guest->v3_ctx,&e);
+ v3_deliver_keyboard_event(guest->v3_ctx, &e);
return 0;
}
-static int palacios_graphics_console_mouse(struct palacios_graphics_console *cons, uint8_t x, uint8_t y, uint8_t buttons)
+static int palacios_graphics_console_mouse(struct v3_guest * guest,
+ struct palacios_graphics_console *cons,
+ uint8_t x, uint8_t y, uint8_t buttons)
{
struct v3_mouse_event e;
e.data[0]=x;
e.data[1]=y;
e.data[2]=buttons; // These three are completely wrong, of course - ignoring mouse for now
- v3_deliver_mouse_event(cons->guest->v3_ctx,&e);
+ v3_deliver_mouse_event(guest->v3_ctx,&e);
return 0;
}
};
-int palacios_init_graphics_console( void ) {
+static int graphics_console_init( void ) {
V3_Init_Graphics_Console(&palacios_graphics_console_hooks);
}
-int palacios_graphics_console_user_query(struct palacios_graphics_console *cons,
- struct v3_fb_query_response __user *u)
-{
+static int fb_query(struct v3_guest * guest, unsigned int cmd, unsigned long arg,
+ void * priv_data) {
+
+ struct palacios_graphics_console * cons = priv_data;
struct v3_fb_query_response q;
- if (copy_from_user(&q,(void __user *) u, sizeof(struct v3_fb_query_response))) {
+ if (copy_from_user(&q, (void __user *) arg, sizeof(struct v3_fb_query_response))) {
printk("palacios: copy from user in getting query in fb\n");
return -EFAULT;
}
printk("palacios: unable to copy fb content to user\n");
return -EFAULT;
}
- q.updated=1;
+ q.updated = 1;
}
break;
}
// now we'll copy back any changes we made to the query/response structure
- if (copy_to_user((void __user *) u, (void*)&q, sizeof(struct v3_fb_query_response))) {
+ if (copy_to_user((void __user *) arg, (void*)&q, sizeof(struct v3_fb_query_response))) {
printk("palacios: unable to copy fb response to user\n");
return -EFAULT;
}
}
-int palacios_graphics_console_user_input(struct palacios_graphics_console *cons,
- struct v3_fb_input __user *u)
-{
+static int fb_input(struct v3_guest * guest,
+ unsigned int cmd,
+ unsigned long arg,
+ void * priv_data) {
+
+ struct palacios_graphics_console * cons = priv_data;
struct v3_fb_input inp;
- int rc=0;
+ int rc = 0;
- if (copy_from_user(&inp,(void __user *) u, sizeof(struct v3_fb_input))) {
+ if (copy_from_user(&inp, (void __user *) arg, sizeof(struct v3_fb_input))) {
printk("palacios: copy from user in getting input in fb\n");
return -EFAULT;
}
- if (inp.data_type==V3_FB_KEY || inp.data_type==V3_FB_BOTH) {
- rc = palacios_graphics_console_key(cons,inp.scan_code);
+ if ((inp.data_type == V3_FB_KEY) || (inp.data_type == V3_FB_BOTH)) {
+ rc = palacios_graphics_console_key(guest, cons, inp.scan_code);
}
- if (inp.data_type==V3_FB_MOUSE || inp.data_type==V3_FB_BOTH) {
- rc |= palacios_graphics_console_mouse(cons,inp.mouse_data[0],inp.mouse_data[1],inp.mouse_data[2]);
+ if ((inp.data_type == V3_FB_MOUSE) || (inp.data_type == V3_FB_BOTH)) {
+ rc |= palacios_graphics_console_mouse(guest, cons, inp.mouse_data[0],
+ inp.mouse_data[1], inp.mouse_data[2]);
}
if (rc) {
return 0;
}
}
+
+
+static int graphics_console_guest_init(struct v3_guest * guest, void ** vm_data) {
+ struct palacios_graphics_console * graphics_cons = kmalloc(sizeof(struct palacios_graphics_console), GFP_KERNEL);
+
+ if (!graphics_cons) {
+ printk("palacios: filed to do guest_init for graphics console\n");
+ return -1;
+ }
+
+ memset(graphics_cons, 0, sizeof(struct palacios_graphics_console));
+
+ *vm_data = graphics_cons;
+
+ add_guest_ctrl(guest, V3_VM_FB_INPUT, fb_input, graphics_cons);
+ add_guest_ctrl(guest, V3_VM_FB_QUERY, fb_query, graphics_cons);
+
+ return 0;
+}
+
+
+
+static struct linux_ext graphics_cons_ext = {
+ .name = "GRAPHICS_CONSOLE_INTERFACE",
+ .init = graphics_console_init,
+ .deinit = NULL,
+ .guest_init = graphics_console_guest_init,
+ .guest_deinit = NULL
+};
+
+
+register_extension(&graphics_cons_ext);
#include <interfaces/vmm_graphics_console.h>
-struct palacios_graphics_console {
- // descriptor for the data in the shared frame buffer
- struct v3_frame_buffer_spec spec;
- // the actual shared frame buffer
- // Note that "shared" here means shared between palacios and us
- // This data could of course also be shared with userland
- void *data;
-
- struct v3_guest * guest;
-
- int cons_refcount;
- int data_refcount;
-
- uint32_t num_updates;
-
- // Currently keystrokes and mouse movements are ignored
-
- // currently, we will not worry about locking this
- // lock_t ...
-};
// This is the data structure that is passed back and forth with user-land
};
-int palacios_init_graphics_console(void);
-
-int palacios_graphics_console_user_query(struct palacios_graphics_console *cons,
- struct v3_fb_query_response __user *fb);
-
-int palacios_graphics_console_user_input(struct palacios_graphics_console *cons,
- struct v3_fb_input __user *in);
#endif
#include <interfaces/vmm_host_dev.h>
#include "palacios.h"
-#include "palacios-host-dev.h"
#include "palacios-host-dev-user.h"
-
-
+#include "linux-exts.h"
+#include "palacios-vm.h"
/*
There are two things in this file:
// 1 on success, negative on error
}
+ Note that the current model has deferred rendezvous and allows
+ for user-side device disconnection and reconnection. It is important
+ to note that this implementation does NOT deal with state discrepency
+ between the palacios-side and the user-side. For example, a user-side
+ device can disconnect, a palacios-side request can then fail, and
+ when the user-side device reconnects, it is unaware of this failure.
*/
+struct palacios_host_dev {
+ spinlock_t lock;
+ struct list_head devs;
+};
+
+
#define MAX_URL 256
#define RENDEZVOUS_WAIT_SECS 60
-
-int connect_host_dev(struct v3_guest * guest, char *url)
+static int host_dev_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data)
{
+ void __user * argp = (void __user *)arg;
+ char url[MAX_URL];
+ struct palacios_host_dev * host_dev = priv_data;
struct palacios_host_device_user *dev;
unsigned long f1, f2;
int i;
+
+
+ if (copy_from_user(url, argp, MAX_URL)) {
+ printk("copy from user error getting url for host device connect...\n");
+ return -EFAULT;
+ }
+
// currently only support user: types:
if (strncasecmp(url,"user:",5)) {
ERROR("palacios: do not currently support host devices of type in \"%s\"\n",url);
// URL. If we don't find it after a while, we give up
for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) {
- spin_lock_irqsave(&(guest->hostdev.lock),f1);
- list_for_each_entry(dev,&(guest->hostdev.devs), node) {
+ spin_lock_irqsave(&(host_dev->lock),f1);
+ list_for_each_entry(dev,&(host_dev->devs), node) {
if (!strncasecmp(url,dev->url,MAX_URL)) {
// found it
spin_lock_irqsave(&(dev->lock),f2);
if (dev->connected) {
ERROR("palacios: device for \"%s\" is already connected!\n",url);
spin_unlock_irqrestore(&(dev->lock),f2);
- spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+ spin_unlock_irqrestore(&(host_dev->lock),f1);
return -1;
} else {
dev->fd = anon_inode_getfd("v3-hostdev", &host_dev_fops, dev, 0);
if (dev->fd<0) {
ERROR("palacios: cannot create fd for device \"%s\"\n",url);
spin_unlock_irqrestore(&(dev->lock),f2);
- spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+ spin_unlock_irqrestore(&(host_dev->lock),f1);
return -1;
}
dev->connected=1;
}
INFO("palacios: connected fd for device \"%s\"\n",url);
spin_unlock_irqrestore(&(dev->lock),f2);
- spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+ spin_unlock_irqrestore(&(host_dev->lock),f1);
return dev->fd;
}
spin_unlock_irqrestore(&(dev->lock),f2);
}
}
- spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+ spin_unlock_irqrestore(&(host_dev->lock),f1);
ssleep(RENDEZVOUS_RETRY_SECS);
}
**************************************************************************************/
-static v3_host_dev_t palacios_host_dev_open(char *url,
- v3_bus_class_t bus,
- v3_guest_dev_t gdev,
- void *host_priv_data)
+
+/* Attempt to rendezvous with the user device if no device is currently connected */
+static int palacios_host_dev_rendezvous(struct palacios_host_device_user *dev)
+{
+ unsigned long f;
+ int i;
+
+ if (dev->connected) {
+ return 0;
+ }
+
+
+ INFO("palacios: attempting new rendezvous for host device \"%s\"\n",dev->url);
+
+ // Now wait until we are noticed!
+ for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) {
+ spin_lock_irqsave(&(dev->lock),f);
+ if (dev->connected) {
+ INFO("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
+ spin_unlock_irqrestore(&(dev->lock),f);
+ return 0;
+ }
+ spin_unlock_irqrestore(&(dev->lock),f);
+ ssleep(RENDEZVOUS_RETRY_SECS);
+ }
+
+ ERROR("palacios: timeout waiting for user side to connect to host device \"%s\"",dev->url);
+
+ // We stay in the list because a future rendezvous might happen
+
+ return -1;
+}
+
+
+/* Creates the device without rendezvous */
+static v3_host_dev_t palacios_host_dev_open_deferred(char *url,
+ v3_bus_class_t bus,
+ v3_guest_dev_t gdev,
+ void *host_priv_data)
{
struct v3_guest *guest= (struct v3_guest*)host_priv_data;
struct palacios_host_device_user *dev;
- unsigned long f1,f2;
- int i;
+ struct palacios_host_dev * host_dev = NULL;
+ unsigned long f;
/*
I will create the device in the list and then wait
for the user side to attach
*/
+ if (guest == NULL) {
+ return 0;
+ }
+
+
+ host_dev = get_vm_ext_data(guest, "HOST_DEVICE_INTERFACE");
+
+ if (host_dev == NULL) {
+ printk("Error locating vm host data for HOST_DEVICE_INTERFACE\n");
+ return 0;
+ }
+
if (strncasecmp(url,"user:",5)) {
ERROR("palacios: do not currently support devices of type in \"%s\"\n",url);
}
// Check to see if a device of this url already exists, which would be ugly
- spin_lock_irqsave(&(guest->hostdev.lock),f1);
- list_for_each_entry(dev,&(guest->hostdev.devs), node) {
+ spin_lock_irqsave(&(host_dev->lock),f);
+ list_for_each_entry(dev,&(host_dev->devs), node) {
if (!strncasecmp(url,dev->url,MAX_URL)) {
// found it
- spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+ spin_unlock_irqrestore(&(host_dev->lock),f);
ERROR("palacios: a host device with url \"%s\" already exists in the guest!\n",url);
return NULL;
}
}
- spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+ spin_unlock_irqrestore(&(host_dev->lock),f);
INFO("palacios: creating host device \"%s\"\n",url);
init_waitqueue_head(&(dev->user_wait_queue));
init_waitqueue_head(&(dev->host_wait_queue));
- INFO("palacios: attempting to rendezvous with user side of host device \"%s\"\n",url);
-
// Insert ourselves into the list
- spin_lock_irqsave(&(guest->hostdev.lock),f1);
- list_add(&(dev->node),&(guest->hostdev.devs));
- spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
+ spin_lock_irqsave(&(host_dev->lock),f);
+ list_add(&(dev->node),&(host_dev->devs));
+ spin_unlock_irqrestore(&(host_dev->lock),f);
+
+ INFO("palacios: host device \"%s\" created with deferred rendezvous\n",url);
+
+ return dev;
-
- // Now wait until we are noticed!
- for (i=0;i<RENDEZVOUS_WAIT_SECS/RENDEZVOUS_RETRY_SECS;i++) {
- spin_lock_irqsave(&(dev->lock),f2);
- if (dev->connected){
- INFO("palacios: connection with user side established for host device \"%s\" fd=%d\n",dev->url,dev->fd);
- spin_unlock_irqrestore(&(dev->lock),f2);
- return dev;
- }
- spin_unlock_irqrestore(&(dev->lock),f2);
- ssleep(RENDEZVOUS_RETRY_SECS);
- }
-
- ERROR("palacios: timeout waiting for user side to connect to host device \"%s\"",url);
-
- // get us out of the list
- spin_lock_irqsave(&(guest->hostdev.lock),f1);
- list_del(&(dev->node));
- spin_unlock_irqrestore(&(guest->hostdev.lock),f1);
-
- palacios_host_dev_user_free(dev);
-
- return NULL;
}
+
+
static int palacios_host_dev_close(v3_host_dev_t hostdev)
{
unsigned long f1, f2;
struct palacios_host_device_user *dev = (struct palacios_host_device_user *) hostdev;
-
+ struct palacios_host_dev * host_dev = NULL;
+
INFO("palacios: closing host device \"%s\"\n",dev->url);
- spin_lock_irqsave(&(dev->guest->hostdev.lock),f1);
+ if ((dev == NULL) || (dev->guest == NULL)) {
+ return -1;
+ }
+
+ host_dev = get_vm_ext_data(dev->guest, "HOST_DEVICE_INTERFACE");
+
+
+ if (host_dev == NULL) {
+ return -1;
+ }
+
+ spin_lock_irqsave(&(host_dev->lock),f1);
spin_lock_irqsave(&(dev->lock),f2);
list_del(&(dev->node));
spin_unlock_irqrestore(&(dev->lock),f2);
- spin_unlock_irqrestore(&(dev->guest->hostdev.lock),f1);
+ spin_unlock_irqrestore(&(host_dev->lock),f1);
palacios_host_dev_user_free(dev);
spin_lock_irqsave(&(dev->lock),f);
- if (dev->waiting) {
+ if (palacios_host_dev_rendezvous(dev)) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: guest issued i/o read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+ ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
return 0;
}
- if (!dev->connected) {
+ if (dev->waiting) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+ ERROR("palacios: guest issued i/o read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
return 0;
}
+
// resize request (no data)
spin_lock_irqsave(&(dev->lock),f);
- if (dev->waiting) {
+ if (palacios_host_dev_rendezvous(dev)) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: guest issued memory read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+ ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
return 0;
}
- if (!dev->connected) {
+
+ if (dev->waiting) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+ ERROR("palacios: guest issued memory read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
return 0;
}
spin_lock_irqsave(&(dev->lock),f);
- if (dev->waiting) {
+ if (palacios_host_dev_rendezvous(dev)) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: guest issued config read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+ ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
return 0;
}
- if (!dev->connected) {
+
+ if (dev->waiting) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+ ERROR("palacios: guest issued config read request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
return 0;
}
spin_lock_irqsave(&(dev->lock),f);
- if (dev->waiting) {
+ if (palacios_host_dev_rendezvous(dev)) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: guest issued i/o write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+ ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
return 0;
}
- if (!dev->connected) {
+
+ if (dev->waiting) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+ ERROR("palacios: guest issued i/o write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
return 0;
}
spin_lock_irqsave(&(dev->lock),f);
- if (dev->waiting) {
+ if (palacios_host_dev_rendezvous(dev)) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: guest issued memory write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+ ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
return 0;
}
- if (!dev->connected) {
+
+ if (dev->waiting) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+ ERROR("palacios: guest issued memory write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
return 0;
}
spin_lock_irqsave(&(dev->lock),f);
- if (dev->waiting) {
+ if (palacios_host_dev_rendezvous(dev)) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: guest issued config write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
+ ERROR("palacios: ignoring request as user side is not connected (and did not rendezvous) for host device \"%s\"\n",dev->url);
return 0;
}
- if (!dev->connected) {
+
+ if (dev->waiting) {
spin_unlock_irqrestore(&(dev->lock),f);
- ERROR("palacios: ignoring request as user side is not connected for host device \"%s\"\n",dev->url);
+ ERROR("palacios: guest issued config write request with host device \"%s\" in wrong state (waiting=%d, connected=%d)\n",dev->url,dev->waiting,dev->connected);
return 0;
}
static struct v3_host_dev_hooks palacios_host_dev_hooks = {
- .open = palacios_host_dev_open,
+ .open = palacios_host_dev_open_deferred,
.close = palacios_host_dev_close,
.read_io = palacios_host_dev_read_io,
.write_io = palacios_host_dev_write_io,
-int palacios_init_host_dev( void )
-{
+static int host_dev_init( void ) {
V3_Init_Host_Device_Support(&palacios_host_dev_hooks);
return 0;
}
+
+
+static int host_dev_guest_init(struct v3_guest * guest, void ** vm_data ) {
+ struct palacios_host_dev * host_dev = kmalloc(sizeof(struct palacios_host_dev), GFP_KERNEL);
+
+ if (!host_dev) {
+ ERROR("palacios: failed to do guest_init for host device\n");
+ return -1;
+ }
+
+
+ INIT_LIST_HEAD(&(host_dev->devs));
+ spin_lock_init(&(host_dev->lock));
+
+ *vm_data = host_dev;
+
+
+ add_guest_ctrl(guest, V3_VM_HOST_DEV_CONNECT, host_dev_connect, host_dev);
+
+ return 0;
+}
+
+
+
+
+
+static struct linux_ext host_dev_ext = {
+ .name = "HOST_DEVICE_INTERFACE",
+ .init = host_dev_init,
+ .deinit = NULL,
+ .guest_init = host_dev_guest_init,
+ .guest_deinit = NULL
+};
+
+
+register_extension(&host_dev_ext);
+++ /dev/null
-/*
- * Palacios Host Device Interface + User-space interface
- * (c) Peter Dinda, 2011
- */
-
-#ifndef __PALACIOS_HOST_DEV_H__
-#define __PALACIOS_HOST_DEV_H__
-
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include "palacios-host-dev-user.h"
-
-struct v3_guest;
-
-/*
- This is the collection of host devices that
- a single guest has
-*/
-struct palacios_host_dev {
- spinlock_t lock;
- struct list_head devs;
-};
-
-
-
-int connect_host_dev(struct v3_guest * guest, char *url);
-
-int palacios_init_host_dev( void );
-
-
-#endif
#include <interfaces/inspector.h>
#include "palacios.h"
+#include "palacios-vm.h"
+#include "linux-exts.h"
struct dentry * v3_dir = NULL;
-int palacios_init_inspector( void ) {
-
- v3_dir = debugfs_create_dir("v3vee", NULL);
-
- if (IS_ERR(v3_dir)) {
- printk("Error creating v3vee debugfs directory\n");
- return -1;
- }
-
- return 0;
-}
-
-
-int palacios_deinit_inspector( void ) {
- debugfs_remove(v3_dir);
- return 0;
-}
}
-int inspect_vm(struct v3_guest * guest) {
+static int inspect_vm(struct v3_guest * guest, unsigned int cmd, unsigned long arg,
+ void * priv_data) {
v3_inspect_node_t * root = v3_get_inspection_root(guest->v3_ctx);
struct dentry * guest_dir = NULL;
dfs_register_tree(guest_dir, root);
return 0;
}
+
+
+
+static int init_inspector( void ) {
+
+ v3_dir = debugfs_create_dir("v3vee", NULL);
+
+ if (IS_ERR(v3_dir)) {
+ printk("Error creating v3vee debugfs directory\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int deinit_inspector( void ) {
+ debugfs_remove(v3_dir);
+ return 0;
+}
+
+
+static int guest_init(struct v3_guest * guest, void ** vm_data) {
+
+ add_guest_ctrl(guest, V3_VM_INSPECT, inspect_vm, NULL);
+ return 0;
+}
+
+static int guest_deinit(struct v3_guest * guest, void * vm_data) {
+
+ return 0;
+}
+
+
+struct linux_ext inspector_ext = {
+ .name = "INSPECTOR",
+ .init = init_inspector,
+ .deinit = deinit_inspector,
+ .guest_init = guest_init,
+ .guest_deinit = guest_deinit
+};
+
+
+register_extension(&inspector_ext);
+++ /dev/null
-/*
- * DebugFS interface
- * (c) Jack Lange, 2011
- */
-
-#include "palacios.h"
-
-int palacios_init_inspector( void );
-int palacios_deinit_inspector( void );
-
-
-
-int inspect_vm(struct v3_guest * guest);
-
#include "palacios.h"
-#include "palacios-keyed-stream.h"
#include "palacios-hashtable.h"
+#include "linux-exts.h"
#define sint64_t int64_t
#include <interfaces/vmm_keyed_stream.h>
};
-int palacios_init_keyed_streams()
+static int init_keyed_streams( void )
{
streams = palacios_create_htable(DEF_NUM_STREAMS,hash_func,hash_comp);
}
-int palacios_deinit_keyed_streams()
+static int deinit_keyed_streams( void )
{
printk("DEINIT OF PALACIOS KEYED STREAMS NOT IMPLEMENTED - WE HAVE JUST LEAKED MEMORY!\n");
return -1;
}
+
+
+static struct linux_ext key_stream_ext = {
+ .name = "KEYED_STREAM_INTERFACE",
+ .init = init_keyed_streams,
+ .deinit = deinit_keyed_streams,
+ .guest_init = NULL,
+ .guest_deinit = NULL
+};
+
+
+register_extension(&key_stream_ext);
+++ /dev/null
-/*
- * Palacios VM Keyed Stream Interface (for checkpoint/restore)
- * Copyright (c) 2011 Peter Dinda <pdinda@northwestern.edu>
- */
-
-#ifndef __PALACIOS_KEYED_STREAM_H__
-#define __PALACIOS_KEYED_STREAM_H__
-
-
-
-int palacios_init_keyed_streams(void);
-int palacios_deinit_keyed_streams(void);
-
-
-#endif
#include <palacios/vmm_host_events.h>
#include <vnet/vnet.h>
+
#define __V3VEE__
#include <palacios/vmm_hashtable.h>
#include <palacios/vmm_ethernet.h>
#undef __V3VEE__
#include "palacios.h"
-#include "palacios-packet.h"
-
+#include "linux-exts.h"
struct palacios_packet_state {
struct socket * raw_sock;
uint8_t inited;
size = sock_sendmsg(packet_state.raw_sock, &msg, len);
set_fs(oldfs);
- if(vnet_debug >= 4){
- printk("Palacios Packet: send pkt to NIC (size: %d)\n", len);
- print_hex_dump(NULL, "pkt_header: ", 0, 20, 20, pkt, 20, 0);
- printk("palacios_packet_send return: %d\n", size);
- }
return size;
}
}
-void
+static void
send_raw_packet_to_palacios(char * pkt,
int len,
struct v3_vm_info * vm) {
break;
}
- if(vnet_debug >= 4){
- printk("Palacios Packet: receive pkt from NIC (size: %d)\n",size);
- print_hex_dump(NULL, "pkt_header: ", 0, 10, 10, pkt, 20, 0);
- }
/* if VNET is enabled, send to VNET */
// ...
}
-int palacios_init_packet(const char * eth_dev) {
+static int packet_init( void ) {
+
+ const char * eth_dev = NULL;
if(packet_state.inited == 0){
packet_state.inited = 1;
packet_state.server_thread = kthread_run(packet_server, NULL, "raw-packet-server");
}
+
+ // REGISTER GLOBAL CONTROL to add devices...
+
return 0;
}
-void palacios_deinit_packet(const char * eth_dev) {
+static int packet_deinit( void ) {
+
kthread_stop(packet_state.server_thread);
packet_state.raw_sock->ops->release(packet_state.raw_sock);
v3_free_htable(packet_state.mac_vm_cache, 0, 1);
packet_state.inited = 0;
+
+ return 0;
}
+
+
+static struct linux_ext pkt_ext = {
+ .name = "PACKET_INTERFACE",
+ .init = packet_init,
+ .deinit = packet_deinit,
+ .guest_init = NULL,
+ .guest_deinit = NULL
+};
+
+
+register_extension(&pkt_ext);
+++ /dev/null
-/*
- * Palacios VM Raw Packet interface
- * (c) Lei Xia, 2010
- */
-
-#ifndef __PALACIOS_PACKET_H__
-#define __PALACIOS_PACKET_H__
-
-int palacios_init_packet(const char * eth_dev);
-int palacios_deinit_packet(void);
-
-#endif
#include <linux/list.h>
#include "palacios.h"
+#include "linux-exts.h"
struct palacios_socket {
static struct list_head global_sockets;
+
+// currently just the list of created sockets
+struct vm_socket_state {
+ struct list_head socket_list;
+};
+
+
//ignore the arguments given here currently
static void *
-palacios_tcp_socket(
- const int bufsize,
- const int nodelay,
- const int nonblocking,
- void * private_data
-)
-{
+palacios_tcp_socket(const int bufsize, const int nodelay,
+ const int nonblocking, void * private_data) {
struct v3_guest * guest = (struct v3_guest *)private_data;
struct palacios_socket * sock = NULL;
+ struct vm_socket_state * vm_state = NULL;
int err;
+ if (guest != NULL) {
+ vm_state = get_vm_ext_data(guest, "SOCKET_INTERFACE");
+
+ if (vm_state == NULL) {
+ printk("ERROR: Could not locate vm socket state for extension SOCKET_INTERFACE\n");
+ return NULL;
+ }
+ }
+
+
sock = kmalloc(sizeof(struct palacios_socket), GFP_KERNEL);
memset(sock, 0, sizeof(struct palacios_socket));
if (guest == NULL) {
list_add(&(sock->sock_node), &global_sockets);
} else {
- list_add(&(sock->sock_node), &(guest->sockets));
+ list_add(&(sock->sock_node), &(vm_state->socket_list));
}
return sock;
{
struct v3_guest * guest = (struct v3_guest *)private_data;
struct palacios_socket * sock = NULL;
+ struct vm_socket_state * vm_state = NULL;
int err;
+ if (guest != NULL) {
+ vm_state = get_vm_ext_data(guest, "SOCKET_INTERFACE");
+
+ if (vm_state == NULL) {
+ printk("ERROR: Could not locate vm socket state for extension SOCKET_INTERFACE\n");
+ return NULL;
+ }
+ }
+
+
sock = kmalloc(sizeof(struct palacios_socket), GFP_KERNEL);
memset(sock, 0, sizeof(struct palacios_socket));
if (guest == NULL) {
list_add(&(sock->sock_node), &global_sockets);
} else {
- list_add(&(sock->sock_node), &(guest->sockets));
+ list_add(&(sock->sock_node), &(vm_state->socket_list));
}
return sock;
return sock->sock->ops->listen(sock->sock, backlog);
}
-static void *
-palacios_accept(
- const void * sock_ptr,
- unsigned int * remote_ip,
- unsigned int * port
-)
-{
+static void * palacios_accept(const void * sock_ptr, unsigned int * remote_ip, unsigned int * port) {
+
struct palacios_socket * sock = (struct palacios_socket *)sock_ptr;
struct palacios_socket * newsock = NULL;
+ struct vm_socket_state * vm_state = NULL;
int err;
if (sock == NULL) {
return NULL;
}
+ if (sock->guest != NULL) {
+ vm_state = get_vm_ext_data(sock->guest, "SOCKET_INTERFACE");
+
+ if (vm_state == NULL) {
+ printk("ERROR: Could not locate vm socket state for extension SOCKET_INTERFACE\n");
+ return NULL;
+ }
+ }
+
+
newsock = kmalloc(sizeof(struct palacios_socket), GFP_KERNEL);
err = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &(newsock->sock));
if (sock->guest == NULL) {
list_add(&(newsock->sock_node), &global_sockets);
} else {
- list_add(&(newsock->sock_node), &(sock->guest->sockets));
+ list_add(&(newsock->sock_node), &(vm_state->socket_list));
}
return newsock;
return err;
}
-struct v3_socket_hooks palacios_sock_hooks = {
+static struct v3_socket_hooks palacios_sock_hooks = {
.tcp_socket = palacios_tcp_socket,
.udp_socket = palacios_udp_socket,
.close = palacios_close,
.recvfrom_ip = palacios_recvfrom_ip,
};
-int palacios_socket_init( void ) {
+static int socket_init( void ) {
V3_Init_Sockets(&palacios_sock_hooks);
INIT_LIST_HEAD(&global_sockets);
return 0;
}
-void palacios_socket_deinit( void ) {
+static int socket_deinit( void ) {
if (!list_empty(&(global_sockets))) {
printk("Error removing module with open sockets\n");
}
+
+ return 0;
}
+
+static struct linux_ext socket_ext = {
+ .name = "SOCKET_INTERFACE",
+ .init = socket_init,
+ .deinit = socket_deinit,
+ .guest_init = NULL,
+ .guest_deinit = NULL
+};
+
+register_extension(&socket_ext);
+++ /dev/null
-/*
- * Palacios VM Raw Packet interface
- * (c) Lei Xia, 2010
- */
-
-#ifndef __PALACIOS_SOCKET_H__
-#define __PALACIOS_SOCKET_H__
-
-int palacios_socket_init(void);
-int palacios_socket_deinit(void);
-
-#endif
#include <linux/errno.h>
#include <linux/percpu.h>
#include <linux/sched.h>
+#include <linux/uaccess.h>
+
#include <interfaces/vmm_stream.h>
-#include "palacios-stream.h"
+#include "linux-exts.h"
+#include "palacios-ringbuffer.h"
+#include "palacios-vm.h"
+
+#define STREAM_BUF_SIZE 1024
+#define STREAM_NAME_LEN 128
+
+
static struct list_head global_streams;
+struct stream_buffer {
+ char name[STREAM_NAME_LEN];
+ struct ringbuf * buf;
+
+ wait_queue_head_t intr_queue;
+ spinlock_t lock;
+
+ struct v3_guest * guest;
+ struct list_head stream_node;
+};
+
+
+// Currently just the list of open streams
+struct vm_stream_state {
+ struct list_head open_streams;
+};
+
static int stream_enqueue(struct stream_buffer * stream, char * buf, int len) {
int bytes = 0;
}
-int stream_dequeue(struct stream_buffer * stream, char * buf, int len) {
+static int stream_dequeue(struct stream_buffer * stream, char * buf, int len) {
int bytes = 0;
bytes = ringbuf_read(stream->buf, buf, len);
return bytes;
}
-int stream_datalen(struct stream_buffer * stream){
+static int stream_datalen(struct stream_buffer * stream){
return ringbuf_data_len(stream->buf);
}
-int open_stream(const char * name) {
- return -1;
-}
-struct stream_buffer * find_stream_by_name(struct v3_guest * guest, const char * name) {
+static struct stream_buffer * find_stream_by_name(struct v3_guest * guest, const char * name) {
struct stream_buffer * stream = NULL;
struct list_head * stream_list = NULL;
+ struct vm_stream_state * vm_state = NULL;
+
if (guest == NULL) {
stream_list = &global_streams;
} else {
- stream_list = &(guest->streams);
+ vm_state = get_vm_ext_data(guest, "STREAM_INTERFACE");
+
+ if (vm_state == NULL) {
+ printk("ERROR: Could not locate vm stream state for extension STREAM_INTERFACE\n");
+ return NULL;
+ }
+
+ stream_list = &(vm_state->open_streams);
}
list_for_each_entry(stream, stream_list, stream_node) {
static void * palacios_stream_open(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;
+
+ if (guest != NULL) {
+ vm_state = get_vm_ext_data(guest, "STREAM_INTERFACE");
+
+ if (vm_state == NULL) {
+ printk("ERROR: Could not locate vm stream state for extension STREAM_INTERFACE\n");
+ return NULL;
+ }
+ }
if (find_stream_by_name(guest, name) != NULL) {
printk("Stream already exists\n");
if (guest == NULL) {
list_add(&(stream->stream_node), &(global_streams));
} else {
- list_add(&(stream->stream_node), &(guest->streams));
+ list_add(&(stream->stream_node), &(vm_state->open_streams));
}
return stream;
}
-struct v3_stream_hooks palacios_stream_hooks = {
+static struct v3_stream_hooks palacios_stream_hooks = {
.open = palacios_stream_open,
.write = palacios_stream_write,
.close = palacios_stream_close,
};
-void palacios_init_stream() {
+static int stream_init( void ) {
INIT_LIST_HEAD(&(global_streams));
V3_Init_Stream(&palacios_stream_hooks);
+
+ return 0;
}
-void palacios_deinit_stream() {
+static int stream_deinit( void ) {
if (!list_empty(&(global_streams))) {
printk("Error removing module with open streams\n");
}
+
+ return 0;
}
+
+static int stream_connect(struct v3_guest * guest, unsigned int cmd, unsigned long arg, void * priv_data) {
+ void __user * argp = (void __user *)arg;
+ char path_name[STREAM_NAME_LEN];
+
+ if (copy_from_user(path_name, argp, STREAM_NAME_LEN)) {
+ printk("%s(%d): copy from user error...\n", __FILE__, __LINE__);
+ return -EFAULT;
+ }
+
+ printk("ERROR: Opening Streams is currently not implemented...\n");
+
+ return -EFAULT;
+}
+
+
+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);
+
+ 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;
+ if (!list_empty(&(state->open_streams))) {
+ printk("Error shutting down VM with open streams\n");
+ }
+
+ return 0;
+}
+
+
+
+static struct linux_ext stream_ext = {
+ .name = "STREAM_INTERFACE",
+ .init = stream_init,
+ .deinit = stream_deinit,
+ .guest_init = guest_stream_init,
+ .guest_deinit = guest_stream_deinit
+};
+
+
+register_extension(&stream_ext);
+++ /dev/null
-/*
- * Palacios Stream interface
- * (c) Lei Xia, 2010
- */
-
-#ifndef __PALACIOS_STREAM_H__
-#define __PALACIOS_STREAM_H__
-
-#include <linux/spinlock.h>
-#include <linux/interrupt.h>
-#include "palacios.h"
-#include "palacios-ringbuffer.h"
-
-#define _V3VEE_
-//#include <palacios/vmm_ringbuffer.h>
-#undef _V3VEE_
-
-#define STREAM_BUF_SIZE 1024
-#define STREAM_NAME_LEN 128
-
-struct stream_buffer {
- char name[STREAM_NAME_LEN];
- struct ringbuf * buf;
-
- wait_queue_head_t intr_queue;
- spinlock_t lock;
-
- struct v3_guest * guest;
- struct list_head stream_node;
-};
-
-
-void palacios_init_stream(void);
-void palacios_deinit_stream(void);
-
-int stream_dequeue(struct stream_buffer * stream, char * buf, int len);
-int stream_datalen(struct stream_buffer * stream);
-
-struct stream_buffer * find_stream_by_name(struct v3_guest * guest, const char * name);
-
-int open_stream(const char * name);
-#endif
-
#include <linux/smp_lock.h>
#include <linux/file.h>
#include <linux/spinlock.h>
-
+#include <linux/rbtree.h>
#include <palacios/vmm.h>
#include "palacios.h"
#include "palacios-vm.h"
+#include "linux-exts.h"
+
+
+struct vm_ctrl {
+ unsigned int cmd;
+
+ int (*handler)(struct v3_guest * guest,
+ unsigned int cmd, unsigned long arg,
+ void * priv_data);
+
+ void * priv_data;
+
+ struct rb_node tree_node;
+};
+
+
+static inline struct vm_ctrl * __insert_ctrl(struct v3_guest * vm,
+ struct vm_ctrl * ctrl) {
+ struct rb_node ** p = &(vm->vm_ctrls.rb_node);
+ struct rb_node * parent = NULL;
+ struct vm_ctrl * tmp_ctrl = NULL;
+
+ while (*p) {
+ parent = *p;
+ tmp_ctrl = rb_entry(parent, struct vm_ctrl, tree_node);
+
+ if (ctrl->cmd < tmp_ctrl->cmd) {
+ p = &(*p)->rb_left;
+ } else if (ctrl->cmd > tmp_ctrl->cmd) {
+ p = &(*p)->rb_right;
+ } else {
+ return tmp_ctrl;
+ }
+ }
+
+ rb_link_node(&(ctrl->tree_node), parent, p);
+
+ return NULL;
+}
+
+
+
+int add_guest_ctrl(struct v3_guest * guest, unsigned int cmd,
+ int (*handler)(struct v3_guest * guest,
+ unsigned int cmd, unsigned long arg,
+ void * priv_data),
+ void * priv_data) {
+ struct vm_ctrl * ctrl = kmalloc(sizeof(struct vm_ctrl), GFP_KERNEL);
+
+ if (ctrl == NULL) {
+ printk("Error: Could not allocate vm ctrl %d\n", cmd);
+ return -1;
+ }
+
+ ctrl->cmd = cmd;
+ ctrl->handler = handler;
+ ctrl->priv_data = priv_data;
+
+ if (__insert_ctrl(guest, ctrl) != NULL) {
+ printk("Could not insert guest ctrl %d\n", cmd);
+ kfree(ctrl);
+ return -1;
+ }
+
+ rb_insert_color(&(ctrl->tree_node), &(guest->vm_ctrls));
+
+ return 0;
+}
+
+
+static struct vm_ctrl * get_ctrl(struct v3_guest * guest, unsigned int cmd) {
+ struct rb_node * n = guest->vm_ctrls.rb_node;
+ struct vm_ctrl * ctrl = NULL;
+
+ while (n) {
+ ctrl = rb_entry(n, struct vm_ctrl, tree_node);
+
+ if (cmd < ctrl->cmd) {
+ n = n->rb_left;
+ } else if (cmd > ctrl->cmd) {
+ n = n->rb_right;
+ } else {
+ return ctrl;
+ }
+ }
+
+ return NULL;
+}
+
-#ifdef V3_CONFIG_STREAM
-#include "palacios-stream.h"
-#endif
-#ifdef V3_CONFIG_CONSOLE
-#include "palacios-console.h"
-#endif
-#ifdef V3_CONFIG_EXT_INSPECTOR
-#include "palacios-inspector.h"
-#endif
-#ifdef V3_CONFIG_GRAPHICS_CONSOLE
-#include "palacios-graphics-console.h"
-#endif
-#ifdef V3_CONFIG_HOST_DEVICE
-#include "palacios-host-dev.h"
-#define HOST_DEV_URL_LEN 256
-#endif
extern struct class * v3_class;
-#define STREAM_NAME_LEN 128
+
static long v3_vm_ioctl(struct file * filp,
unsigned int ioctl, unsigned long arg) {
break;
}
- case V3_VM_CONSOLE_CONNECT: {
-#ifdef V3_CONFIG_CONSOLE
- return connect_console(guest);
-#else
- printk("Console support not available\n");
- return -EFAULT;
-#endif
- break;
- }
-
- case V3_VM_STREAM_CONNECT: {
-#ifdef V3_CONFIG_STREAM
- void __user * argp = (void __user *)arg;
- char path_name[STREAM_NAME_LEN];
+ default: {
+ struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
- if (copy_from_user(path_name, argp, STREAM_NAME_LEN)) {
- printk("%s(%d): copy from user error...\n", __FILE__, __LINE__);
- return -EFAULT;
+ if (ctrl) {
+ return ctrl->handler(guest, ioctl, arg, ctrl->priv_data);
}
-
- return open_stream(path_name);
-#else
- printk("Stream support Not available\n");
- return -EFAULT;
-#endif
- break;
- }
-
- case V3_VM_HOST_DEV_CONNECT: {
-#ifdef V3_CONFIG_HOST_DEVICE
- void __user * argp = (void __user *)arg;
- char host_dev_url[HOST_DEV_URL_LEN];
-
- if (copy_from_user(host_dev_url, argp, HOST_DEV_URL_LEN)) {
- printk("copy from user error getting url for host device connect...\n");
- return -EFAULT;
- }
-
- return connect_host_dev(guest,host_dev_url);
-#else
- printk("palacios: Host device support not available\n");
- return -EFAULT;
-#endif
- break;
- }
-
- case V3_VM_FB_INPUT:
-#ifdef V3_CONFIG_GRAPHICS_CONSOLE
- return palacios_graphics_console_user_input(&(guest->graphics_console),
- (struct v3_fb_input __user *) arg) ;
-#else
- return -EFAULT;
-#endif
- break;
- case V3_VM_FB_QUERY:
-#ifdef V3_CONFIG_GRAPHICS_CONSOLE
- return palacios_graphics_console_user_query(&(guest->graphics_console),
- (struct v3_fb_query_response __user *) arg);
-#else
- return -EFAULT;
-#endif
- break;
-
-
- default:
- printk("\tUnhandled\n");
+
+ printk("\tUnhandled ctrl cmd: %d\n", ioctl);
return -EINVAL;
+ }
}
return 0;
// allow_signal(SIGKILL);
unlock_kernel();
+ init_vm_extensions(guest);
+
+ guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
+
+ if (guest->v3_ctx == NULL) {
+ printk("palacios: failed to create vm\n");
+ complete(&(guest->start_done));
+ return -1;
+ }
+
printk("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
if (err) {
printk("Fails to add cdev\n");
+ v3_free_vm(guest->v3_ctx);
complete(&(guest->start_done));
return -1;
}
if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){
printk("Fails to create device\n");
cdev_del(&(guest->cdev));
- complete(&(guest->start_done));
- return -1;
- }
-
- guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
-
- if (guest->v3_ctx == NULL) {
- printk("palacios: failed to create vm\n");
- cdev_del(&(guest->cdev));
+ v3_free_vm(guest->v3_ctx);
complete(&(guest->start_done));
return -1;
}
printk("palacios: launching vm\n");
-
-#ifdef V3_CONFIG_EXT_INSPECTOR
- inspect_vm(guest);
-#endif
-
-
if (v3_start_vm(guest->v3_ctx, 0xffffffff) < 0) {
printk("palacios: launch of vm failed\n");
device_destroy(v3_class, guest->vm_dev);
int start_palacios_vm(void * arg);
int stop_palacios_vm(struct v3_guest * guest);
+
+int add_guest_ctrl(struct v3_guest * guest, unsigned int cmd,
+ int (*handler)(struct v3_guest * guest,
+ unsigned int cmd, unsigned long arg,
+ void * priv_data),
+ void * priv_data);
+
+
+
#endif
-int palacios_vnet_init( void ) {
+static int vnet_init( void ) {
init_vnet(&vnet_host_hooks);
vnet_bridge_init();
}
-void palacios_vnet_deinit( void ) {
+static int vnet_deinit( void ) {
deinit_vnet();
vnet_bridge_deinit();
vnet_ctrl_deinit();
printk("V3 VNET Deinited\n");
+
+ return 0;
}
+static struct linux_ext vnet_ext = {
+ .name = "VNET",
+ .init = vnet_init,
+ .deinit = vnet_deinit,
+ .guest_init = NULL,
+ .guest_deinit = NULL
+};
+
+register_extension(&vnet_ext);
#include <linux/sched.h>
#include <linux/slab.h>
-#ifdef V3_CONFIG_CONSOLE
-#include "palacios-console.h"
-#endif
-
-#ifdef V3_CONFIG_GRAPHICS_CONSOLE
-#include "palacios-graphics-console.h"
-#endif
-
-#ifdef V3_CONFIG_HOST_DEVICE
-#include "palacios-host-dev.h"
-#endif
-
/* Global Control IOCTLs */
#define V3_START_GUEST 10
#define V3_VM_STREAM_CONNECT 21
#define V3_VM_STOP 22
+#define V3_VM_INSPECT 30
+
#define V3_VM_FB_INPUT (256+1)
#define V3_VM_FB_QUERY (256+2)
unsigned long long num_pages;
};
-struct v3_network {
- unsigned char socket;
- unsigned char packet;
- unsigned char vnet;
-};
void * trace_malloc(size_t size, gfp_t flags);
void trace_free(const void * objp);
char name[128];
- struct list_head files;
- struct list_head streams;
- struct list_head sockets;
-
-#ifdef V3_CONFIG_CONSOLE
- struct palacios_console console;
-#endif
-
-#ifdef V3_CONFIG_GRAPHICS_CONSOLE
- struct palacios_graphics_console graphics_console;
-#endif
-
-#ifdef V3_CONFIG_HOST_DEVICE
- struct palacios_host_dev hostdev;
-#endif
+ struct rb_root vm_ctrls;
+ struct list_head exts;
struct completion start_done;
struct completion thread_done;
-
-
-extern void send_key_to_palacios(unsigned char status, unsigned char scan_code);
-
-
int palacios_vmm_init( void );
int palacios_vmm_exit( void );
*/
#define MASK_DISPLACEMENT(reg, mode) ({ \
sint64_t val = 0; \
- if (mode == DISP8) { \
+ if (mode == DISP0) { \
+ val = reg; \
+ } else if (mode == DISP8) { \
val = (sint8_t)(reg & 0xff); \
} else if (mode == DISP16) { \
val = (sint16_t)(reg & 0xffff); \
#define ADDR_MASK(val, length) ({ \
ullong_t mask = 0x0LL; \
switch (length) { \
+ case 1: \
+ mask = 0x0000000000000ffLL; \
+ break; \
case 2: \
mask = 0x00000000000fffffLL; \
break; \
mod_mode = DISP8;
} else if (modrm->mod == 2) {
mod_mode = DISP16;
+ } else {
+ PrintError("Instruction format error: Invalid mod_rm mode (%d)\n", modrm->mod);
+ v3_print_instr(instr);
+ return -1;
}
switch (modrm->rm) {
case 0:
- base_addr = gprs->rbx + MASK_DISPLACEMENT(gprs->rsi, mod_mode);
+ base_addr = gprs->rbx + ADDR_MASK(gprs->rsi, 2);
break;
case 1:
- base_addr = gprs->rbx + MASK_DISPLACEMENT(gprs->rdi, mod_mode);
+ base_addr = gprs->rbx + ADDR_MASK(gprs->rdi, 2);
break;
case 2:
- base_addr = gprs->rbp + MASK_DISPLACEMENT(gprs->rsi, mod_mode);
+ base_addr = gprs->rbp + ADDR_MASK(gprs->rsi, 2);
break;
case 3:
- base_addr = gprs->rbp + MASK_DISPLACEMENT(gprs->rdi, mod_mode);
+ base_addr = gprs->rbp + ADDR_MASK(gprs->rdi, 2);
break;
case 4:
- base_addr = gprs->rsi;
+ base_addr = ADDR_MASK(gprs->rsi, 2);
break;
case 5:
- base_addr = gprs->rdi;
+ base_addr = ADDR_MASK(gprs->rdi, 2);
break;
case 6:
if (modrm->mod == 0) {
base_addr = 0;
mod_mode = DISP16;
} else {
- base_addr = gprs->rbp;
+ base_addr = ADDR_MASK(gprs->rbp, 2);
}
break;
case 7:
- base_addr = gprs->rbx;
+ base_addr = ADDR_MASK(gprs->rbx, 2);
break;
}
mod_mode = DISP8;
} else if (modrm->mod == 2) {
mod_mode = DISP32;
+ } else {
+ PrintError("Instruction format error: Invalid mod_rm mode (%d)\n", modrm->mod);
+ v3_print_instr(instr);
+ return -1;
}
switch (modrm->rm) {
mod_mode = DISP8;
} else if (modrm->mod == 2) {
mod_mode = DISP32;
+ } else {
+ PrintError("Instruction format error: Invalid mod_rm mode (%d)\n", modrm->mod);
+ v3_print_instr(instr);
+ return -1;
}
if (rm_val == 4) {