--- /dev/null
+KERNELDIR := ../../linux-2.6.32.y/
+CONFIG_PALACIOS_PATH := /home/jarusl/palacios
+
+
+
+
+v3vee-objs := palacios.o palacios-dev.o palacios-vm.o palacios-file.o palacios-stream.o palacios-console.o palacios-mm.o palacios-serial.o palacios-queue.o palacios-ringbuffer.o
+#palacios-socket.o
+#palacios-vnet.o palacios-packet.o
+
+v3vee-objs += ../../palacios/libv3vee.a
+
+
+obj-m := v3vee.o
+
+
+LDFLAGS = --whole-archive --script=$(PWD)/link.cmd
+
+
+EXTRA_CFLAGS := -I$(CONFIG_PALACIOS_PATH)/palacios/include/ -DMODULE=1 -D__KERNEL__=1
+
+
+
+all:
+ $(MAKE) -C $(KERNELDIR) M=$(PWD) modules
+
+
+clean:
+ $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
+
+install:
+ $(MAKE) -C $(KERNELDIR) M=$(PWD) modules_install /sbin/ -ae
+
--- /dev/null
+SECTIONS
+{
+ _v3_devices :
+ {
+ __start__v3_devices = .;
+ *(_v3_devices);
+ __stop__v3_devices = .;
+
+ }
+
+/* _v3_capsules :
+ {
+ __start__v3_capsules = .;
+ *(_v3_capsules);
+ __stop__v3_capsules = .;
+ }
+*/
+ _v3_shdw_pg_impls :
+ {
+ __start__v3_shdw_pg_impls = .;
+ *(_v3_shdw_pg_impls);
+ __stop__v3_shdw_pg_impls = .;
+
+ }
+ _v3_extensions :
+ {
+ __start__v3_extensions = .;
+ *(_v3_extensions);
+ __stop__v3_extensions = .;
+
+ }
+}
+
--- /dev/null
+/*
+ * VM Console
+ * (c) Jack Lange, 2010
+ */
+
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
+#include <linux/sched.h>
+
+#include <palacios/vmm_console.h>
+#include <palacios/vmm_host_events.h>
+
+#include "palacios.h"
+#include "palacios-console.h"
+#include "palacios-queue.h"
+
+typedef enum { CONSOLE_CURS_SET = 1,
+ CONSOLE_CHAR_SET = 2,
+ CONSOLE_SCROLL = 3,
+ CONSOLE_UPDATE = 4,
+ CONSOLE_RESOLUTION = 5} console_op_t;
+
+
+
+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));
+
+
+/* This is overkill...*/
+#define CONSOLE_QUEUE_LEN 8096
+
+
+static ssize_t
+console_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
+ struct palacios_console * cons = filp->private_data;
+ struct cons_msg * msg = NULL;
+ unsigned long flags;
+ int entries = 0;
+
+ if (cons->open == 0) {
+ return 0;
+ }
+
+
+ if (size < sizeof(struct cons_msg)) {
+ printk("Invalid Read operation size: %lu\n", size);
+ return -EFAULT;
+ }
+
+ msg = dequeue(cons->queue);
+
+ if (msg == NULL) {
+ printk("ERROR: Null console message\n");
+ return -EFAULT;
+ }
+
+ if (copy_to_user(buf, msg, size)) {
+ printk("Read Fault\n");
+ return -EFAULT;
+ }
+
+
+ kfree(msg);
+
+ spin_lock_irqsave(&(cons->queue->lock), flags);
+ entries = cons->queue->num_entries;
+ spin_unlock_irqrestore(&(cons->queue->lock), flags);
+
+ if (entries > 0) {
+ wake_up_interruptible(&(cons->intr_queue));
+ }
+
+ // printk("Read from console\n");
+ return size;
+}
+
+
+static ssize_t
+console_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
+ struct palacios_console * cons = filp->private_data;
+ int i = 0;
+ struct v3_keyboard_event event = {0, 0};
+
+ if (cons->open == 0) {
+ return 0;
+ }
+
+
+ for (i = 0; i < size; i++) {
+ if (copy_from_user(&(event.scan_code), buf, 1)) {
+ printk("Console Write fault\n");
+ return -EFAULT;
+ }
+
+ v3_deliver_keyboard_event(cons->guest->v3_ctx, &event);
+ }
+
+ return size;
+}
+
+static unsigned int
+console_poll(struct file * filp, struct poll_table_struct * poll_tb) {
+ struct palacios_console * cons = filp->private_data;
+ unsigned int mask = POLLIN | POLLRDNORM;
+ unsigned long flags;
+ int entries = 0;
+
+ // printk("Console=%p (guest=%s)\n", cons, cons->guest->name);
+
+
+ poll_wait(filp, &(cons->intr_queue), poll_tb);
+
+ spin_lock_irqsave(&(cons->queue->lock), flags);
+ entries = cons->queue->num_entries;
+ spin_unlock_irqrestore(&(cons->queue->lock), flags);
+
+ if (entries > 0) {
+ // printk("Returning from POLL\n");
+ return mask;
+ }
+
+ return 0;
+}
+
+
+static int console_release(struct inode * i, struct file * filp) {
+ struct palacios_console * cons = filp->private_data;
+ struct cons_msg * msg = NULL;
+ unsigned long flags;
+
+ printk("Releasing the Console File desc\n");
+
+ spin_lock_irqsave(&(cons->queue->lock), flags);
+ cons->connected = 0;
+ spin_unlock_irqrestore(&(cons->queue->lock), flags);
+
+ while ((msg = dequeue(cons->queue))) {
+ kfree(msg);
+ }
+
+ return 0;
+}
+
+
+static struct file_operations cons_fops = {
+ .read = console_read,
+ .write = console_write,
+ .poll = console_poll,
+ .release = console_release,
+};
+
+
+
+int connect_console(struct v3_guest * guest) {
+ struct palacios_console * cons = &(guest->console);
+ int cons_fd = 0;
+ unsigned long flags;
+
+ if (cons->open == 0) {
+ printk("Attempted to connect to unopened console\n");
+ return -1;
+ }
+
+ spin_lock_irqsave(&(cons->lock), flags);
+
+ cons_fd = anon_inode_getfd("v3-cons", &cons_fops, cons, 0);
+
+ if (cons_fd < 0) {
+ printk("Error creating console inode\n");
+ return cons_fd;
+ }
+
+ cons->connected = 1;
+
+ v3_deliver_console_event(guest->v3_ctx, NULL);
+ spin_unlock_irqrestore(&(cons->lock), flags);
+
+ printk("Console connected\n");
+
+ return cons_fd;
+}
+
+
+
+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);
+
+ printk("Guest initialized virtual console (Guest=%s)\n", guest->name);
+
+ if (guest == NULL) {
+ printk("ERROR: Cannot open a console on a NULL guest\n");
+ return NULL;
+ }
+
+ if (cons->open == 1) {
+ printk("Console already open\n");
+ return NULL;
+ }
+
+
+ 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;
+
+
+ return cons;
+}
+
+static int post_msg(struct palacios_console * cons, struct cons_msg * msg) {
+ // printk("Posting Console message\n");
+
+ while (enqueue(cons->queue, msg) == -1) {
+ wake_up_interruptible(&(cons->intr_queue));
+ schedule();
+ }
+
+ wake_up_interruptible(&(cons->intr_queue));
+
+ return 0;
+}
+
+
+static int palacios_tty_cursor_set(void * console, int x, int y) {
+ struct palacios_console * cons = (struct palacios_console *)console;
+ struct cons_msg * msg = NULL;
+
+ if (cons->connected == 0) {
+ return 0;
+ }
+
+ msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
+
+ msg->op = CONSOLE_CURS_SET;
+ msg->cursor.x = x;
+ msg->cursor.y = y;
+
+ return post_msg(cons, msg);
+}
+
+static int palacios_tty_character_set(void * console, int x, int y, char c, unsigned char style) {
+ struct palacios_console * cons = (struct palacios_console *) console;
+ struct cons_msg * msg = NULL;
+
+ if (cons->connected == 0) {
+ return 0;
+ }
+
+ msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
+
+ msg->op = CONSOLE_CHAR_SET;
+ msg->character.x = x;
+ msg->character.y = y;
+ msg->character.c = c;
+ msg->character.style = style;
+
+ return post_msg(cons, msg);
+}
+
+static int palacios_tty_scroll(void * console, int lines) {
+ struct palacios_console * cons = (struct palacios_console *) console;
+ struct cons_msg * msg = NULL;
+
+
+ if (cons->connected == 0) {
+ return 0;
+ }
+
+ msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
+
+ msg->op = CONSOLE_SCROLL;
+ msg->scroll.lines = lines;
+
+ return post_msg(cons, msg);
+}
+
+static int palacios_set_text_resolution(void * console, int cols, int rows) {
+ struct palacios_console * cons = (struct palacios_console *)console;
+ struct cons_msg * msg = NULL;
+
+ if (cons->connected == 0) {
+ return 0;
+ }
+
+ msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
+
+ msg->op = CONSOLE_RESOLUTION;
+ msg->resolution.cols = cols;
+ msg->resolution.rows = rows;
+
+ return post_msg(cons, msg);
+}
+
+static int palacios_tty_update(void * console) {
+ struct palacios_console * cons = (struct palacios_console *) console;
+ struct cons_msg * msg = NULL;
+
+ if (cons->connected == 0) {
+ return 0;
+ }
+
+ msg = kmalloc(sizeof(struct cons_msg), GFP_KERNEL);
+
+ msg->op = CONSOLE_UPDATE;
+
+ return post_msg(cons, msg);
+}
+
+static void palacios_tty_close(void * console) {
+ struct palacios_console * cons = (struct palacios_console *) console;
+
+ cons->open = 0;
+}
+
+
+
+static struct v3_console_hooks palacios_console_hooks = {
+ .open = palacios_tty_open,
+ .set_cursor = palacios_tty_cursor_set,
+ .set_character = palacios_tty_character_set,
+ .scroll = palacios_tty_scroll,
+ .set_text_resolution = palacios_set_text_resolution,
+ .update = palacios_tty_update,
+ .close = palacios_tty_close,
+};
+
+
+
+int palacios_init_console( void ) {
+ V3_Init_Console(&palacios_console_hooks);
+
+ return 0;
+}
--- /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
--- /dev/null
+/*
+ Palacios main control interface
+ (c) Jack Lange, 2010
+ */
+
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/percpu.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+
+#include <linux/io.h>
+
+#include <linux/file.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
+
+#include "palacios.h"
+#include "palacios-mm.h"
+#include "palacios-vm.h"
+#include "palacios-stream.h"
+#include "palacios-file.h"
+#include "palacios-serial.h"
+
+MODULE_LICENSE("GPL");
+
+
+static int v3_major_num = 0;
+
+static u8 v3_minor_map[MAX_VMS / 8] = {[0 ... (MAX_VMS / 8) - 1] = 0};
+
+
+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;
+
+ for (i = 0; i < sizeof(v3_minor_map); i++) {
+ if (v3_minor_map[i] != 0xff) {
+ for (j = 0; j < 8; j++) {
+ if (!v3_minor_map[i] & (0x1 << j)) {
+ avail = 1;
+ v3_minor_map[i] |= (0x1 << j);
+ break;
+ }
+ }
+
+ if (avail == 1) {
+ break;
+ }
+ }
+ }
+
+ if (avail == 0) {
+ return -1;
+ }
+
+ return (i * 8) + j;
+}
+
+
+
+static long v3_dev_ioctl(struct file * filp,
+ unsigned int ioctl, unsigned long arg) {
+ void __user * argp = (void __user *)arg;
+ printk("V3 IOCTL %d\n", ioctl);
+
+
+ switch (ioctl) {
+ case V3_START_GUEST:{
+ struct v3_guest_img user_image;
+ struct v3_guest * guest = kmalloc(sizeof(struct v3_guest), GFP_KERNEL);
+ int vm_minor = 0;
+
+ if (IS_ERR(guest)) {
+ printk("Error allocating Kernel guest_image\n");
+ return -EFAULT;
+ }
+
+ memset(guest, 0, sizeof(struct v3_guest));
+
+ printk("Starting V3 Guest...\n");
+
+ vm_minor = register_vm();
+
+ if (vm_minor == -1) {
+ printk("Too many VMs are currently running\n");
+ return -EFAULT;
+ }
+
+ guest->vm_dev = MKDEV(v3_major_num, vm_minor);
+
+ if (copy_from_user(&user_image, argp, sizeof(struct v3_guest_img))) {
+ printk("copy from user error getting guest image...\n");
+ return -EFAULT;
+ }
+
+ guest->img_size = user_image.size;
+
+ printk("Allocating kernel memory for guest image (%llu bytes)\n", user_image.size);
+ guest->img = kmalloc(guest->img_size, GFP_KERNEL);
+
+ if (IS_ERR(guest->img)) {
+ printk("Error: Could not allocate space for guest image\n");
+ return -EFAULT;
+ }
+
+ if (copy_from_user(guest->img, user_image.guest_data, guest->img_size)) {
+ printk("Error loading guest data\n");
+ return -EFAULT;
+ }
+
+ strncpy(guest->name, user_image.name, 127);
+
+ printk("Launching VM\n");
+
+ INIT_LIST_HEAD(&(guest->streams));
+ INIT_LIST_HEAD(&(guest->files));
+ INIT_LIST_HEAD(&(guest->sockets));
+ init_completion(&(guest->thread_done));
+
+ kthread_run(start_palacios_vm, guest, guest->name);
+
+ wait_for_completion(&(guest->thread_done));
+
+ return guest->vm_dev;
+ break;
+ }
+ case V3_ADD_MEMORY: {
+ struct v3_mem_region mem;
+
+ memset(&mem, 0, sizeof(struct v3_mem_region));
+
+ if (copy_from_user(&mem, argp, sizeof(struct v3_mem_region))) {
+ printk("copy from user error getting mem_region...\n");
+ return -EFAULT;
+ }
+
+ printk("Adding %llu pages to Palacios memory\n", mem.num_pages);
+
+ if (add_palacios_memory(mem.base_addr, mem.num_pages) == -1) {
+ printk("Error adding memory to Palacios\n");
+ return -EFAULT;
+ }
+
+ // Mem test...
+ /*
+ {
+ void * vaddr = __va(alloc_palacios_pgs(131072, 4096));
+ memset(vaddr, 0xfe492fe2, mem.num_pages * 4096);
+ }
+ */
+
+ break;
+ }
+ default:
+ printk("\tUnhandled\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+
+static struct file_operations v3_ctrl_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = v3_dev_ioctl,
+ .compat_ioctl = v3_dev_ioctl,
+};
+
+
+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
+ int ret = 0;
+
+
+ palacios_init_mm();
+
+ v3_class = class_create(THIS_MODULE, "vms");
+ if (IS_ERR(v3_class)) {
+ printk("Failed to register V3 VM device class\n");
+ return PTR_ERR(v3_class);
+ }
+
+ printk("intializing V3 Control device\n");
+
+ ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee");
+
+ if (ret < 0) {
+ printk("Error registering device region for V3 devices\n");
+ goto failure2;
+ }
+
+ v3_major_num = MAJOR(dev);
+
+ dev = MKDEV(v3_major_num, MAX_VMS + 1);
+
+
+ printk("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev));
+ cdev_init(&ctrl_dev, &v3_ctrl_fops);
+ ctrl_dev.owner = THIS_MODULE;
+ ctrl_dev.ops = &v3_ctrl_fops;
+ cdev_add(&ctrl_dev, dev, 1);
+
+ device_create(v3_class, NULL, dev, NULL, "v3vee");
+
+ if (ret != 0) {
+ printk("Error adding v3 control device\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();
+
+ palacios_init_stream();
+ palacios_file_init();
+ palacios_init_console();
+
+
+
+ return 0;
+
+ failure1:
+ unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
+ failure2:
+ class_destroy(v3_class);
+
+ return ret;
+}
+
+static void __exit v3_exit(void) {
+ extern u32 pg_allocs;
+ extern u32 pg_frees;
+ extern u32 mallocs;
+ extern u32 frees;
+
+ printk("Removing V3 Control device\n");
+
+ palacios_vmm_exit();
+
+
+ printk("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
+ printk("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
+
+
+ unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
+}
+
+
+
+module_init(v3_init);
+module_exit(v3_exit);
--- /dev/null
+/* Palacios file interface
+ * (c) Jack Lange, 2010
+ */
+
+
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+
+#include "palacios.h"
+
+#include <palacios/vmm_file.h>
+
+static struct list_head global_files;
+
+struct palacios_file {
+ struct file * filp;
+
+ char * path;
+ int mode;
+
+ spinlock_t lock;
+
+ struct v3_guest * guest;
+
+
+ struct list_head file_node;
+};
+
+
+
+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;
+
+ pfile = kmalloc(sizeof(struct palacios_file), GFP_KERNEL);
+ memset(pfile, 0, sizeof(struct palacios_file));
+
+ if ((mode & FILE_OPEN_MODE_READ) && (mode & FILE_OPEN_MODE_WRITE)) {
+ pfile->mode = O_RDWR;
+ } else if (mode & FILE_OPEN_MODE_READ) {
+ pfile->mode = O_RDONLY;
+ } else if (mode & FILE_OPEN_MODE_WRITE) {
+ pfile->mode = O_WRONLY;
+ }
+
+ pfile->filp = filp_open(path, pfile->mode, 0);
+
+ if (pfile->filp == NULL) {
+ printk("Cannot open file: %s\n", path);
+ return NULL;
+ }
+
+ pfile->path = kmalloc(strlen(path) + 1, GFP_KERNEL);
+ strncpy(pfile->path, path, strlen(path));
+ pfile->guest = guest;
+
+ spin_lock_init(&(pfile->lock));
+
+ if (guest == NULL) {
+ list_add(&(pfile->file_node), &(global_files));
+ } else {
+ list_add(&(pfile->file_node), &(guest->files));
+ }
+
+
+ return pfile;
+}
+
+static int palacios_file_close(void * file_ptr) {
+ struct palacios_file * pfile = (struct palacios_file *)file_ptr;
+
+ filp_close(pfile->filp, NULL);
+
+ list_del(&(pfile->file_node));
+
+ kfree(pfile);
+
+ return 0;
+}
+
+static long long palacios_file_size(void * file_ptr) {
+ struct palacios_file * pfile = (struct palacios_file *)file_ptr;
+ struct file * filp = pfile->filp;
+ struct kstat s;
+ int ret;
+
+ ret = vfs_getattr(filp->f_path.mnt, filp->f_path.dentry, &s);
+
+ if (ret != 0) {
+ printk("Failed to fstat file\n");
+ return -1;
+ }
+
+ return s.size;
+}
+
+static long long palacios_file_read(void * file_ptr, void * buffer, long long length, long long offset){
+ struct palacios_file * pfile = (struct palacios_file *)file_ptr;
+ struct file * filp = pfile->filp;
+ ssize_t ret;
+ mm_segment_t old_fs;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+
+ ret = vfs_read(filp, buffer, length, &offset);
+
+ set_fs(old_fs);
+
+ if (ret <= 0) {
+ printk("sys_read of %p for %lld bytes failed\n", filp, length);
+ }
+
+ return ret;
+}
+
+
+static long long palacios_file_write(void * file_ptr, void * buffer, long long length, long long offset) {
+ struct palacios_file * pfile = (struct palacios_file *)file_ptr;
+ struct file * filp = pfile->filp;
+ mm_segment_t old_fs;
+ ssize_t ret;
+
+ old_fs = get_fs();
+ set_fs(get_ds());
+
+ ret = vfs_write(filp, buffer, length, &offset);
+
+ set_fs(old_fs);
+
+
+ if (ret <= 0) {
+ printk("sys_write failed\n");
+ }
+
+ return ret;
+}
+
+
+static struct v3_file_hooks palacios_file_hooks = {
+ .open = palacios_file_open,
+ .close = palacios_file_close,
+ .read = palacios_file_read,
+ .write = palacios_file_write,
+ .size = palacios_file_size,
+};
+
+
+int palacios_file_init( void ) {
+ INIT_LIST_HEAD(&(global_files));
+
+ V3_Init_File(&palacios_file_hooks);
+
+ return 0;
+}
--- /dev/null
+#ifndef __PALACIOS_FILE_H__
+#define __PALACISO_FILE_H__
+
+int palacios_file_init(void);
+
+#endif
--- /dev/null
+/* Palacios memory manager
+ * (c) Jack Lange, 2010
+ */
+
+#include <asm/page_64_types.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+//static struct list_head pools;
+
+
+struct mempool {
+ uintptr_t base_addr;
+ u64 num_pages;
+
+ u8 * bitmap;
+};
+
+
+static struct mempool pool;
+
+static inline int get_page_bit(int index) {
+ int major = index / 8;
+ int minor = index % 8;
+
+ return (pool.bitmap[major] & (0x1 << minor));
+}
+
+static inline void set_page_bit(int index) {
+ int major = index / 8;
+ int minor = index % 8;
+
+ pool.bitmap[major] |= (0x1 << minor);
+}
+
+static inline void clear_page_bit(int index) {
+ int major = index / 8;
+ int minor = index % 8;
+
+ pool.bitmap[major] &= ~(0x1 << minor);
+}
+
+
+
+static uintptr_t alloc_contig_pgs(u64 num_pages, u32 alignment) {
+ int step = 1;
+ int i = 0;
+ int start = 0;
+
+ printk("Allocating %llu pages (align=%lu)\n",
+ num_pages, (unsigned long)alignment);
+
+ if (pool.bitmap == NULL) {
+ printk("ERROR: Attempting to allocate from non initialized memory\n");
+ return 0;
+ }
+
+ if (alignment > 0) {
+ step = alignment / 4096;
+ }
+
+ // Start the search at the correct alignment
+ if (pool.base_addr % alignment) {
+ start = ((alignment - (pool.base_addr % alignment)) >> 12);
+ }
+
+ printk("\t Start idx %d (base_addr=%llu)\n", start, (u64)pool.base_addr);
+
+ for (i = start; i < (pool.num_pages - num_pages); i += step) {
+ if (get_page_bit(i) == 0) {
+ int j = 0;
+ int collision = 0;
+
+ for (j = i; (j - i) < num_pages; j++) {
+ if (get_page_bit(j) == 1) {
+ collision = 1;
+ break;
+ }
+ }
+
+ if (collision == 1) {
+ break;
+ }
+
+ for (j = i; (j - i) < num_pages; j++) {
+ set_page_bit(j);
+ }
+
+ return pool.base_addr + (i * 4096);
+ }
+ }
+
+ return 0;
+}
+
+
+// alignment is in bytes
+uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment) {
+ uintptr_t addr = 0;
+
+ if ((num_pages < 12)) {
+ struct page * pgs = NULL;
+ int order = get_order(num_pages * PAGE_SIZE);
+
+ pgs = alloc_pages(GFP_KERNEL, order);
+
+ WARN(!pgs, "Could not allocate pages\n");
+
+ printk("%llu pages (order=%d) aquired from alloc_pages\n",
+ num_pages, order);
+
+ addr = page_to_pfn(pgs) << PAGE_SHIFT;
+ } else {
+ printk("Allocating %llu pages from bitmap allocator\n", num_pages);
+ //addr = pool.base_addr;
+ addr = alloc_contig_pgs(num_pages, alignment);
+ }
+
+
+ printk("Returning from alloc addr=%p, vaddr=%p\n", (void *)addr, __va(addr));
+ return addr;
+}
+
+
+
+void free_palacios_pgs(uintptr_t pg_addr, int num_pages) {
+ printk("Freeing Memory page %p\n", (void *)pg_addr);
+
+ if ((pg_addr >= pool.base_addr) &&
+ (pg_addr < pool.base_addr + (4096 * pool.num_pages))) {
+ int pg_idx = (pg_addr - pool.base_addr) / 4096;
+ int i = 0;
+
+ if ((pg_idx + num_pages) > pool.num_pages) {
+ printk("Freeing memory bounds exceeded\n");
+ return;
+ }
+
+ for (i = 0; i < num_pages; i++) {
+ WARN(get_page_bit(pg_idx + i) == 0, "Trying to free unallocated page\n");
+
+ clear_page_bit(pg_idx + i);
+ }
+ } else {
+ __free_pages(pfn_to_page(pg_addr >> PAGE_SHIFT), get_order(num_pages * PAGE_SIZE));
+ }
+}
+
+
+int add_palacios_memory(uintptr_t base_addr, u64 num_pages) {
+ /* JRL: OK.... so this is horrible, terrible and if anyone else did it I would yell at them.
+ * But... the fact that you can do this in C is so ridiculous that I can't help myself.
+ * Note that we're repurposing "true" to be 1 here
+ */
+
+ int bitmap_size = (num_pages / 8) + ((num_pages % 8) > 0);
+
+ if (pool.num_pages != 0) {
+ printk("ERROR: Memory has already been added\n");
+ return -1;
+ }
+
+ printk("Managing %dMB of memory starting at %llu (%lluMB)\n",
+ (unsigned int)(num_pages * 4096) / (1024 * 1024),
+ (unsigned long long)base_addr,
+ (unsigned long long)(base_addr / (1024 * 1024)));
+
+
+ pool.bitmap = kmalloc(bitmap_size, GFP_KERNEL);
+
+ if (IS_ERR(pool.bitmap)) {
+ printk("Error allocating Palacios MM bitmap\n");
+ return -1;
+ }
+
+ memset(pool.bitmap, 0, bitmap_size);
+
+ pool.base_addr = base_addr;
+ pool.num_pages = num_pages;
+
+ return 0;
+}
+
+
+
+int palacios_init_mm( void ) {
+ // INIT_LIST_HEAD(&(pools));
+ pool.base_addr = 0;
+ pool.num_pages = 0;
+ pool.bitmap = NULL;
+
+ return 0;
+}
--- /dev/null
+/* Palacios memory manager
+ * (c) Jack Lange, 2010
+ */
+
+#ifndef PALACIOS_MM_H
+#define PALACIOS_MM_H
+
+
+
+uintptr_t alloc_palacios_pgs(u64 num_pages, u32 alignment);
+void free_palacios_pg(uintptr_t base_addr);
+void free_palacios_pgs(uintptr_t base_addr, u64 num_pages);
+
+
+int add_palacios_memory(uintptr_t base_addr, u64 num_pages);
+int remove_palacios_memory(uintptr_t base_addr, u64 num_pages);
+int palacios_init_mm( void );
+
+
+
+#endif
--- /dev/null
+/*
+ * VM Raw Packet
+ * (c) Lei Xia, 2010
+ */
+#include <asm/uaccess.h>
+#include <linux/inet.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/preempt.h>
+#include <linux/sched.h>
+#include <linux/if_packet.h>
+#include <linux/errno.h>
+#include <asm/msr.h>
+
+#include <palacios/vmm_packet.h>
+#include <palacios/vmm_host_events.h>
+#include <palacios/vmm_vnet.h>
+
+#include "palacios.h"
+#include "palacios-packet.h"
+
+//#define DEBUG_PALACIOS_PACKET
+
+static struct socket * raw_sock;
+
+static int packet_inited = 0;
+
+static int init_raw_socket (const char * eth_dev){
+ int err;
+ struct sockaddr_ll sock_addr;
+ struct ifreq if_req;
+ int dev_idx;
+
+ err = sock_create(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL), &raw_sock);
+ if (err < 0) {
+ printk(KERN_WARNING "Could not create a PF_PACKET Socket, err %d\n", err);
+ return -1;
+ }
+
+ if(eth_dev == NULL){
+ return 0;
+ }
+
+ memset(&if_req, 0, sizeof(if_req));
+ strncpy(if_req.ifr_name, eth_dev, sizeof(if_req.ifr_name));
+
+ err = raw_sock->ops->ioctl(raw_sock, SIOCGIFINDEX, (long)&if_req);
+ if(err < 0){
+ printk(KERN_WARNING "Palacios Packet: Unable to get index for device %s, error %d\n", if_req.ifr_name, err);
+ dev_idx = 2; /* default "eth0" */
+ }
+ else{
+ dev_idx = if_req.ifr_ifindex;
+ }
+
+ printk(KERN_INFO "Palacios Packet: bind to device index: %d\n", dev_idx);
+
+ memset(&sock_addr, 0, sizeof(sock_addr));
+ sock_addr.sll_family = PF_PACKET;
+ sock_addr.sll_protocol = htons(ETH_P_ALL);
+ sock_addr.sll_ifindex = dev_idx;
+
+ err = raw_sock->ops->bind(raw_sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
+ if (err < 0){
+ printk(KERN_WARNING "Error binding raw packet to device %s, %d\n", eth_dev, err);
+ return -1;
+ }
+
+ printk(KERN_INFO "Bind palacios raw packet interface to device %s\n", eth_dev);
+
+ return 0;
+}
+
+
+static int
+palacios_packet_send(const char * pkt, unsigned int len, void * private_data) {
+ struct msghdr msg;
+ struct iovec iov;
+ mm_segment_t oldfs;
+ int size = 0;
+
+#ifdef DEBUG_PALACIOS_PACKET
+ {
+ printk("Palacios Packet: send pkt to NIC (size: %d)\n",
+ len);
+ //print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt, len, 0);
+ }
+#endif
+
+
+ iov.iov_base = (void *)pkt;
+ iov.iov_len = (__kernel_size_t)len;
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_flags = 0;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ size = sock_sendmsg(raw_sock, &msg, len);
+ set_fs(oldfs);
+
+ return size;
+}
+
+
+static struct v3_packet_hooks palacios_packet_hooks = {
+ .send = palacios_packet_send,
+};
+
+
+static int
+recv_pkt(char * pkt, int len) {
+ struct msghdr msg;
+ struct iovec iov;
+ mm_segment_t oldfs;
+ int size = 0;
+
+ if (raw_sock == NULL) {
+ return -1;
+ }
+
+ iov.iov_base = pkt;
+ iov.iov_len = len;
+
+ msg.msg_flags = 0;
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ size = sock_recvmsg(raw_sock, &msg, len, msg.msg_flags);
+ set_fs(oldfs);
+
+ return size;
+}
+
+
+void
+send_raw_packet_to_palacios(char * pkt,
+ int len,
+ struct v3_vm_info * vm) {
+ struct v3_packet_event event;
+
+ event.pkt = kmalloc(len, GFP_KERNEL);
+ memcpy(event.pkt, pkt, len);
+ event.size = len;
+
+ v3_deliver_packet_event(vm, &event);
+}
+
+static int packet_server(void * arg) {
+ char pkt[ETHERNET_PACKET_LEN];
+ int size;
+
+ printk("Palacios Raw Packet Bridge: Staring receiving server\n");
+
+ while (!kthread_should_stop()) {
+ size = recv_pkt(pkt, ETHERNET_PACKET_LEN);
+ if (size < 0) {
+ printk(KERN_WARNING "Palacios Packet Socket receive error\n");
+ break;
+ }
+
+#ifdef DEBUG_PALACIOS_PACKET
+ {
+ printk("Palacios Packet: receive pkt from NIC (size: %d)\n",
+ size);
+ //print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt, size, 0);
+ }
+#endif
+
+ send_raw_packet_to_palacios(pkt, size, NULL);
+ }
+
+ return 0;
+}
+
+
+int palacios_init_packet(const char * eth_dev) {
+
+ if(packet_inited == 0){
+ packet_inited = 1;
+ init_raw_socket(eth_dev);
+ V3_Init_Packet(&palacios_packet_hooks);
+
+ kthread_run(packet_server, NULL, "raw-packet-server");
+ }
+
+ return 0;
+}
+
--- /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);
+
+#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) 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 <linux/slab.h>
+
+#include "palacios-queue.h"
+
+void init_queue(struct gen_queue * queue, unsigned int max_entries) {
+ queue->num_entries = 0;
+ queue->max_entries = max_entries;
+
+ INIT_LIST_HEAD(&(queue->entries));
+ spin_lock_init(&(queue->lock));
+}
+
+struct gen_queue * create_queue(unsigned int max_entries) {
+ struct gen_queue * tmp_queue = kmalloc(sizeof(struct gen_queue), GFP_KERNEL);
+ init_queue(tmp_queue, max_entries);
+ return tmp_queue;
+}
+
+int enqueue(struct gen_queue * queue, void * entry) {
+ struct queue_entry * q_entry = NULL;
+ unsigned long flags;
+
+ if (queue->num_entries >= queue->max_entries) {
+ return -1;
+ }
+
+ q_entry = kmalloc(sizeof(struct queue_entry), GFP_KERNEL);
+
+ spin_lock_irqsave(&(queue->lock), flags);
+
+ q_entry->entry = entry;
+ list_add_tail(&(q_entry->node), &(queue->entries));
+ queue->num_entries++;
+
+ spin_unlock_irqrestore(&(queue->lock), flags);
+
+ return 0;
+}
+
+
+void * dequeue(struct gen_queue * queue) {
+ void * entry_val = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&(queue->lock), flags);
+
+ if (!list_empty(&(queue->entries))) {
+ struct list_head * q_entry = queue->entries.next;
+ struct queue_entry * tmp_entry = list_entry(q_entry, struct queue_entry, node);
+
+ entry_val = tmp_entry->entry;
+ list_del(q_entry);
+ kfree(tmp_entry);
+
+ queue->num_entries--;
+
+ }
+
+ spin_unlock_irqrestore(&(queue->lock), flags);
+
+ return entry_val;
+}
--- /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".
+ */
+
+
+#ifndef __PALACIOS_QUEUE_H__
+#define __PALACIOS_QUEUE_H__
+
+
+
+#include <linux/list.h>
+#include <linux/spinlock.h>
+
+
+
+struct queue_entry {
+ void * entry;
+ struct list_head node;
+};
+
+
+struct gen_queue {
+ unsigned int num_entries;
+ unsigned int max_entries;
+ struct list_head entries;
+ spinlock_t lock;
+};
+
+
+struct gen_queue * create_queue(unsigned int max_entries);
+void init_queue(struct gen_queue * queue, unsigned int max_entries);
+
+int enqueue(struct gen_queue * queue, void * entry);
+void * dequeue(struct gen_queue * queue);
+
+
+
+
+
+#endif
--- /dev/null
+/* Ringbuffer implementation for Palacios
+ */
+
+#ifndef PALACIOS_RINGBUF_H
+#define PALACIOS_RINGBUF_H
+
+extern struct v3_ringbuf * v3_create_ringbuf(unsigned int size);
+extern void v3_free_ringbuf(struct v3_ringbuf * ring);
+extern int v3_ringbuf_read(struct v3_ringbuf * ring, unsigned char * dst, unsigned int len);
+extern int v3_ringbuf_write(struct v3_ringbuf * ring, unsigned char * src, unsigned int len);
+
+
+
+#endif
--- /dev/null
+/*
+ * Ringbuffer Routines for VM\r
+ * (c) Lei Xia, 2010
+ */\r
+#include <linux/errno.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>\r
+\r
+#include "palacios.h"\r
+#include "palacios-ringbuffer.h"\r
+
+void init_ringbuf(struct ringbuf * ring, unsigned int size) {\r
+ ring->buf = kmalloc(size, GFP_KERNEL);\r
+ ring->size = size;
+
+ ring->start = 0;
+ ring->end = 0;
+ ring->current_len = 0;
+}
+\r
+struct ringbuf * create_ringbuf(unsigned int size) {\r
+ struct ringbuf * ring = (struct ringbuf *)kmalloc(sizeof(struct ringbuf), GFP_KERNEL);\r
+ init_ringbuf(ring, size);\r
+
+ return ring;
+}
+\r
+void free_ringbuf(struct ringbuf * ring) {\r
+ kfree(ring->buf);\r
+ kfree(ring);\r
+}\r
+\r
+static inline unsigned char * get_read_ptr(struct ringbuf * ring) {\r
+ return (unsigned char *)(ring->buf + ring->start);\r
+}
+
+\r
+static inline unsigned char * get_write_ptr(struct ringbuf * ring) {\r
+ return (unsigned char *)(ring->buf + ring->end);\r
+}\r
+\r
+static inline int get_read_section_size(struct ringbuf * ring) {\r
+ return ring->size - ring->start;
+}
+
+\r
+static inline int get_write_section_size(struct ringbuf * ring) {\r
+ return ring->size - ring->end;
+}
+
+\r
+static inline int is_read_loop(struct ringbuf * ring, unsigned int len) {\r
+ if ((ring->start >= ring->end) && (ring->current_len > 0)) {
+ // end is past the end of the buffer
+ if (get_read_section_size(ring) < len) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+\r
+static inline int is_write_loop(struct ringbuf * ring, unsigned int len) {\r
+ if ((ring->end >= ring->start) && (ring->current_len < ring->size)) {
+ // end is past the end of the buffer
+ if (get_write_section_size(ring) < len) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+\r
+static inline int ringbuf_avail_space(struct ringbuf * ring) {\r
+ return ring->size - ring->current_len;
+}
+
+\r
+int ringbuf_data_len(struct ringbuf * ring) {\r
+ return ring->current_len;
+}
+
+\r
+static inline int ringbuf_capacity(struct ringbuf * ring) {\r
+ return ring->size;
+}
+
+\r
+int ringbuf_read(struct ringbuf * ring, unsigned char * dst, unsigned int len) {\r
+ int read_len = 0;
+ int ring_data_len = ring->current_len;
+
+ read_len = (len > ring_data_len) ? ring_data_len : len;
+
+ if (is_read_loop(ring, read_len)) {
+ int section_len = get_read_section_size(ring);
+
+ memcpy(dst, get_read_ptr(ring), section_len);
+ memcpy(dst + section_len, ring->buf, read_len - section_len);
+
+ ring->start = read_len - section_len;
+ } else {
+ memcpy(dst, get_read_ptr(ring), read_len);
+
+ ring->start += read_len;
+ }
+
+ ring->current_len -= read_len;
+
+ return read_len;
+}
+
+\r
+#if 0\r
+\r
+static int ringbuf_peek(struct ringbuf * ring, unsigned char * dst, unsigned int len) {\r
+ int read_len = 0;
+ int ring_data_len = ring->current_len;
+
+ read_len = (len > ring_data_len) ? ring_data_len : len;
+
+ if (is_read_loop(ring, read_len)) {
+ int section_len = get_read_section_size(ring);
+
+ memcpy(dst, get_read_ptr(ring), section_len);
+ memcpy(dst + section_len, ring->buf, read_len - section_len);
+ } else {
+ memcpy(dst, get_read_ptr(ring), read_len);
+ }
+
+ return read_len;
+}
+
+\r
+static int ringbuf_delete(struct ringbuf * ring, unsigned int len) {\r
+ int del_len = 0;
+ int ring_data_len = ring->current_len;
+
+ del_len = (len > ring_data_len) ? ring_data_len : len;
+
+ if (is_read_loop(ring, del_len)) {
+ int section_len = get_read_section_size(ring);
+ ring->start = del_len - section_len;
+ } else {
+ ring->start += del_len;
+ }
+
+ ring->current_len -= del_len;
+ return del_len;
+}
+#endif\r
+\r
+int ringbuf_write(struct ringbuf * ring, unsigned char * src, unsigned int len) {\r
+ int write_len = 0;
+ int ring_avail_space = ring->size - ring->current_len;
+
+ write_len = (len > ring_avail_space) ? ring_avail_space : len;\r
+
+ if (is_write_loop(ring, write_len)) {
+ int section_len = get_write_section_size(ring);
+ \r
+ memcpy(get_write_ptr(ring), src, section_len);
+ ring->end = 0;
+
+ memcpy(get_write_ptr(ring), src + section_len, write_len - section_len);
+
+ ring->end += write_len - section_len;
+ } else {\r
+ memcpy(get_write_ptr(ring), src, write_len);
+
+ ring->end += write_len;
+ }
+
+ ring->current_len += write_len;
+
+ return write_len;
+}
+\r
--- /dev/null
+/*
+ * Ringbuffer Routines for VM\r
+ * (c) Lei Xia, 2010
+ */\r
+
+#ifndef __PALACIOS_RING_BUFFER_H__\r
+#define __PALACIOS_RING_BUFFER_H__\r
+\r
+struct ringbuf {\r
+ unsigned char * buf;\r
+ unsigned int size;\r
+
+ unsigned int start;\r
+ unsigned int end;\r
+ unsigned int current_len;\r
+};
+\r
+\r
+struct ringbuf * create_ringbuf(unsigned int size);\r
+void free_ringbuf(struct ringbuf * ring);\r
+int ringbuf_read(struct ringbuf * ring, unsigned char * dst, unsigned int len);\r
+int ringbuf_write(struct ringbuf * ring, unsigned char * src, unsigned int len);\r
+int ringbuf_data_len(struct ringbuf * ring);\r
+
+#endif\r
+\r
--- /dev/null
+/*
+ * VM Serial Controls
+ * (c) Lei Xia, 2010
+ */
+
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/anon_inodes.h>
+#include <linux/file.h>
+
+#include <palacios/vmm.h>
+#include <palacios/vmm_host_events.h>
+
+#include "palacios.h"
+#include "palacios-stream.h"
+
+
+void
+send_serial_input_to_palacios( unsigned char *input,
+ unsigned int len,
+ struct v3_vm_info * vm ) {
+ struct v3_serial_event event;
+
+ if (len > 128) {
+ len = 128;
+ }
+
+ memcpy(event.data, input, len);
+ event.len = len;
+
+ v3_deliver_serial_event(vm, &event);
+}
+
+static ssize_t
+serial_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
+
+ int len = 0;
+ char temp[128];
+ struct stream_buffer * stream = filp->private_data;
+
+ memset(temp, 0, 128);
+
+ if (size > 128) {
+ size = 128;
+ }
+
+ len = stream_dequeue(stream, temp, size);
+
+ if (copy_to_user(buf, temp, len)) {
+ printk("Read fault\n");
+ return -EFAULT;
+ }
+
+ printk("Returning %d bytes\n", len);
+
+ return len;
+}
+
+static ssize_t
+serial_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
+ char temp[128];
+ struct stream_buffer * stream = filp->private_data;
+ struct v3_vm_info * vm;
+
+ memset(temp, 0, 128);
+
+ if (size > 128) {
+ size = 128;
+ }
+
+ if (copy_from_user(temp, buf, size)) {
+ printk("Write fault\n");
+ return -EFAULT;
+ }
+
+ vm = stream->guest->v3_ctx;
+ send_serial_input_to_palacios(temp, size, vm);
+
+ return size;
+}
+
+
+static unsigned int
+serial_poll(struct file * filp, struct poll_table_struct * poll_tb) {
+ unsigned int mask = 0;
+ struct stream_buffer *stream = filp->private_data;
+
+ poll_wait(filp, &(stream->intr_queue), poll_tb);
+
+ if(stream_datalen(stream) > 0){
+ mask = POLLIN | POLLRDNORM;
+ }
+
+ printk("polling v3 serial\n");
+
+ return mask;
+}
+
+static struct file_operations v3_cons_fops = {
+ .read = serial_read,
+ .write = serial_write,
+ .poll = serial_poll,
+};
+
+
+int open_serial(char * name) {
+ int cons_fd;
+ void *stream;
+
+ printk("open path: %s\n", name);
+
+ stream = find_stream_by_name(NULL, name);
+
+ if (stream == NULL) {
+ return -1;
+ }
+
+ cons_fd = anon_inode_getfd("v3-cons", &v3_cons_fops, stream, 0);
+
+ if (cons_fd < 0) {
+ printk("Error creating serial inode\n");
+ return cons_fd;
+ }
+
+ printk("Returning new serial fd\n");
+
+ return cons_fd;
+}
--- /dev/null
+/*
+ * Palacios VM Stream Serial interface
+ * (c) Jack Lange, 2010
+ */
+
+#ifndef __PALACIOS_SERIAL_H__
+#define __PALACIOS_SERIAL_H__
+
+int open_serial(char * name);
+
+#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) 2010, Lei Xia <lxia@northwestern.edu>
+ * Copyright (c) 2010, The V3VEE Project <http://www.v3vee.org>
+ * All rights reserved.
+ *
+ * This is free software. You are permitted to use, redistribute,
+ * and modify it under the terms of the GNU General Public License
+ * Version 2 (GPLv2). The accompanying COPYING file contains the
+ * full text of the license.
+ */
+
+#include <palacios/vmm_socket.h>
+
+#include <linux/spinlock.h>
+#include <asm/uaccess.h>
+#include <linux/inet.h>
+#include <linux/kthread.h>
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/preempt.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+
+#include "palacios.h"
+
+
+struct palacios_socket {
+ struct socket * sock;
+
+ struct v3_guest * guest;
+ struct list_head sock_node;
+};
+
+static struct list_head global_sockets;
+
+//ignore the arguments given here currently
+static void *
+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;
+ int err;
+
+ sock = kmalloc(sizeof(struct palacios_socket), GFP_KERNEL);
+ memset(sock, 0, sizeof(struct palacios_socket));
+
+ err = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &(sock->sock));
+
+ if (err < 0) {
+ kfree(sock);
+ return NULL;
+ }
+
+ sock->guest = guest;
+
+ if (guest == NULL) {
+ list_add(&(sock->sock_node), &global_sockets);
+ } else {
+ list_add(&(sock->sock_node), &(guest->sockets));
+ }
+
+ return sock;
+}
+
+//ignore the arguments given here currently
+static void *
+palacios_udp_socket(
+ const int bufsize,
+ const int nonblocking,
+ void * private_data
+)
+{
+ struct v3_guest * guest = (struct v3_guest *)private_data;
+ struct palacios_socket * sock = NULL;
+ int err;
+
+ sock = kmalloc(sizeof(struct palacios_socket), GFP_KERNEL);
+ memset(sock, 0, sizeof(struct palacios_socket));
+
+ err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &(sock->sock)) ;
+
+ if (err < 0){
+ kfree(sock);
+ return NULL;
+ }
+
+
+ sock->guest = guest;
+
+ if (guest == NULL) {
+ list_add(&(sock->sock_node), &global_sockets);
+ } else {
+ list_add(&(sock->sock_node), &(guest->sockets));
+ }
+
+ return sock;
+}
+
+
+static void
+palacios_close(void * sock_ptr)
+{
+ struct palacios_socket * sock = (struct palacios_socket *)sock_ptr;
+
+ if (sock != NULL) {
+ sock->sock->ops->release(sock->sock);
+
+ list_del(&(sock->sock_node));
+ kfree(sock);
+ }
+}
+
+static int
+palacios_bind_socket(
+ const void * sock_ptr,
+ const int port
+)
+{
+ struct sockaddr_in addr;
+ struct palacios_socket * sock = (struct palacios_socket *)sock_ptr;
+
+ if (sock == NULL) {
+ return -1;
+ }
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = INADDR_ANY;
+
+ return sock->sock->ops->bind(sock->sock, (struct sockaddr *)&addr, sizeof(addr));
+}
+
+static int
+palacios_listen(
+ const void * sock_ptr,
+ int backlog
+)
+{
+ struct palacios_socket * sock = (struct palacios_socket *)sock_ptr;
+
+ if (sock == NULL) {
+ return -1;
+ }
+
+ return sock->sock->ops->listen(sock->sock, backlog);
+}
+
+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;
+ int err;
+
+ if (sock == NULL) {
+ return NULL;
+ }
+
+ newsock = kmalloc(sizeof(struct palacios_socket), GFP_KERNEL);
+
+ err = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &(newsock->sock));
+
+ if (err < 0) {
+ kfree(newsock);
+ return NULL;
+ }
+
+ newsock->sock->type = sock->sock->type;
+ newsock->sock->ops = sock->sock->ops;
+
+ err = newsock->sock->ops->accept(sock->sock, newsock->sock, 0);
+
+ if (err < 0){
+ kfree(newsock);
+ return NULL;
+ }
+
+ //TODO: How do we get ip & port?
+
+
+ newsock->guest = sock->guest;
+
+ if (sock->guest == NULL) {
+ list_add(&(newsock->sock_node), &global_sockets);
+ } else {
+ list_add(&(newsock->sock_node), &(sock->guest->sockets));
+ }
+
+ return newsock;
+}
+
+static int
+palacios_select(
+ struct v3_sock_set * rset,
+ struct v3_sock_set * wset,
+ struct v3_sock_set * eset,
+ struct v3_timeval tv)
+{
+ //TODO:
+
+ return 0;
+}
+
+static int
+palacios_connect_to_ip(
+ const void * sock_ptr,
+ const int hostip,
+ const int port
+)
+{
+ struct sockaddr_in client;
+ struct palacios_socket * sock = (struct palacios_socket *)sock_ptr;
+
+ if (sock == NULL) {
+ return -1;
+ }
+
+ client.sin_family = AF_INET;
+ client.sin_port = htons(port);
+ client.sin_addr.s_addr = htonl(hostip);
+
+ return sock->sock->ops->connect(sock->sock, (struct sockaddr *)&client, sizeof(client), 0);
+}
+
+static int
+palacios_send(
+ const void * sock_ptr,
+ const char * buf,
+ const int len
+)
+{
+ struct palacios_socket * sock = (struct palacios_socket *)sock_ptr;
+ struct msghdr msg;
+ mm_segment_t oldfs;
+ struct iovec iov;
+ int err = 0;
+
+ if (sock == NULL) {
+ return -1;
+ }
+
+ msg.msg_flags = MSG_NOSIGNAL;//0/*MSG_DONTWAIT*/;;
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ iov.iov_base = (char *)buf;
+ iov.iov_len = (size_t)len;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = sock_sendmsg(sock->sock, &msg, (size_t)len);
+
+ set_fs(oldfs);
+
+ return err;
+}
+
+static int
+palacios_recv(
+ const void * sock_ptr,
+ char * buf,
+ const int len
+)
+{
+
+ struct palacios_socket * sock = (struct palacios_socket *)sock_ptr;
+ struct msghdr msg;
+ mm_segment_t oldfs;
+ struct iovec iov;
+ int err;
+
+ if (sock == NULL) {
+ return -1;
+ }
+
+ msg.msg_flags = 0;
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ iov.iov_base = (void *)&buf[0];
+ iov.iov_len = (size_t)len;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = sock_recvmsg(sock->sock, &msg, (size_t)len, 0/*MSG_DONTWAIT*/);
+
+ set_fs(oldfs);
+
+ return err;
+}
+
+static int
+palacios_sendto_ip(
+ const void * sock_ptr,
+ const int ip_addr,
+ const int port,
+ const char * buf,
+ const int len
+)
+{
+ struct palacios_socket * sock = (struct palacios_socket *)sock_ptr;
+ struct msghdr msg;
+ mm_segment_t oldfs;
+ struct iovec iov;
+ struct sockaddr_in dst;
+ int err = 0;
+
+ if (sock == NULL) {
+ return -1;
+ }
+
+ dst.sin_family = AF_INET;
+ dst.sin_port = htons(port);
+ dst.sin_addr.s_addr = htonl(ip_addr);
+
+ msg.msg_flags = MSG_NOSIGNAL;//0/*MSG_DONTWAIT*/;;
+ msg.msg_name = &dst;
+ msg.msg_namelen = sizeof(struct sockaddr_in);
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ iov.iov_base = (char *)buf;
+ iov.iov_len = (size_t)len;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = sock_sendmsg(sock->sock, &msg, (size_t)len);
+
+ set_fs(oldfs);
+
+ return err;
+}
+
+
+// TODO:
+static int
+palacios_recvfrom_ip(
+ const void * sock_ptr,
+ const int ip_addr,
+ const int port,
+ char * buf,
+ const int len
+)
+{
+ struct palacios_socket * sock = (struct palacios_socket *)sock_ptr;
+ struct sockaddr_in src;
+ int alen;
+ struct msghdr msg;
+ mm_segment_t oldfs;
+ struct iovec iov;
+ int err;
+
+ if (sock == NULL) {
+ return -1;
+ }
+
+ src.sin_family = AF_INET;
+ src.sin_port = htons(port);
+ src.sin_addr.s_addr = htonl(ip_addr);
+ alen = sizeof(src);
+
+
+ msg.msg_flags = 0;
+ msg.msg_name = &src;
+ msg.msg_namelen = sizeof(struct sockaddr_in);
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+
+ iov.iov_base = (void *)&buf[0];
+ iov.iov_len = (size_t)len;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = sock_recvmsg(sock->sock, &msg, (size_t)len, 0/*MSG_DONTWAIT*/);
+
+ set_fs(oldfs);
+
+ return err;
+}
+
+struct v3_socket_hooks palacios_sock_hooks = {
+ .tcp_socket = palacios_tcp_socket,
+ .udp_socket = palacios_udp_socket,
+ .close = palacios_close,
+ .bind = palacios_bind_socket,
+ .listen = palacios_listen,
+ .accept = palacios_accept,
+ .select = palacios_select,
+ .connect_to_ip = palacios_connect_to_ip,
+ .connect_to_host = NULL,
+ .send = palacios_send,
+ .recv = palacios_recv,
+ .sendto_host = NULL,
+ .sendto_ip = palacios_sendto_ip,
+ .recvfrom_host = NULL,
+ .recvfrom_ip = palacios_recvfrom_ip,
+};
+
+int palacios_socket_init( void ) {
+ V3_Init_Sockets(&palacios_sock_hooks);
+ INIT_LIST_HEAD(&global_sockets);
+ return 0;
+}
--- /dev/null
+
+/*
+ * VM specific Controls
+ * (c) Lei Xia, 2010
+ */
+#include <linux/errno.h>
+#include <linux/percpu.h>
+#include <linux/sched.h>
+
+#include <palacios/vmm_stream.h>
+#include "palacios-stream.h"
+#include "palacios-ringbuf.h"
+
+static struct list_head global_streams;
+
+int stream_enqueue(struct stream_buffer * stream, char * buf, int len) {
+ int bytes = 0;
+
+ bytes = ringbuf_write(stream->buf, buf, len);
+
+ return bytes;
+}
+
+
+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){
+ return ringbuf_data_len(stream->buf);
+}
+
+
+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;
+
+ if (guest == NULL) {
+ stream_list = &global_streams;
+ } else {
+ stream_list = &(guest->streams);
+ }
+
+ list_for_each_entry(stream, stream_list, stream_node) {
+ if (strncmp(stream->name, name, STREAM_NAME_LEN) == 0) {
+ return stream;
+ }
+ }
+
+ return NULL;
+}
+
+
+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;
+
+ if (find_stream_by_name(guest, name) != NULL) {
+ printk("Stream already exists\n");
+ return NULL;
+ }
+
+ stream = kmalloc(sizeof(struct stream_buffer), GFP_KERNEL);
+
+ stream->buf = create_ringbuf(STREAM_BUF_SIZE);
+ stream->guest = guest;
+
+ strncpy(stream->name, name, STREAM_NAME_LEN - 1);
+
+ init_waitqueue_head(&(stream->intr_queue));
+ spin_lock_init(&(stream->lock));
+
+ if (guest == NULL) {
+ list_add(&(stream->stream_node), &(global_streams));
+ } else {
+ list_add(&(stream->stream_node), &(guest->streams));
+ }
+
+ return stream;
+}
+
+
+static int palacios_stream_write(void * stream_ptr, char * buf, int len) {
+ struct stream_buffer * stream = (struct stream_buffer *)stream_ptr;
+ int ret = 0;
+
+ ret = stream_enqueue(stream, buf, len);
+
+ if (ret > 0) {
+ wake_up_interruptible(&(stream->intr_queue));
+ }
+
+ return ret;
+}
+
+
+static void palacios_stream_close(void * stream_ptr) {
+ struct stream_buffer * stream = (struct stream_buffer *)stream_ptr;
+
+ free_ringbuf(stream->buf);
+ list_del(&(stream->stream_node));
+ kfree(stream);
+
+}
+
+struct v3_stream_hooks palacios_stream_hooks = {
+ .open = palacios_stream_open,
+ .write = palacios_stream_write,
+ .close = palacios_stream_close,
+};
+
+
+void palacios_init_stream() {
+ INIT_LIST_HEAD(&(global_streams));
+ V3_Init_Stream(&palacios_stream_hooks);
+}
+
+
--- /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 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);
+int stream_enqueue(struct stream_buffer * stream, char * buf, int len);
+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);
+
+#endif
+
--- /dev/null
+/*
+ * VM specific Controls
+ * (c) Jack Lange, 2010
+ */
+
+#include <linux/device.h>
+#include <linux/cdev.h>
+#include <linux/errno.h>
+#include <linux/percpu.h>
+#include <linux/fs.h>
+#include <linux/uaccess.h>
+#include <linux/poll.h>
+#include <linux/anon_inodes.h>
+#include <linux/sched.h>
+
+#include <linux/smp_lock.h>
+#include <linux/file.h>
+#include <linux/spinlock.h>
+
+
+#include <palacios/vmm.h>
+
+#include "palacios.h"
+#include "palacios-console.h"
+#include "palacios-serial.h"
+#include "palacios-vm.h"
+
+extern struct class * v3_class;
+#define STREAM_NAME_LEN 128
+
+static long v3_vm_ioctl(struct file * filp,
+ unsigned int ioctl, unsigned long arg) {
+ void __user * argp = (void __user *)arg;
+ char path_name[STREAM_NAME_LEN];
+
+ struct v3_guest * guest = filp->private_data;
+
+ printk("V3 IOCTL %d\n", ioctl);
+
+ switch (ioctl) {
+
+ case V3_VM_CONSOLE_CONNECT: {
+ return connect_console(guest);
+ break;
+ }
+ case V3_VM_SERIAL_CONNECT: {
+ if (copy_from_user(path_name, argp, STREAM_NAME_LEN)) {
+ printk("copy from user error getting guest image...\n");
+ return -EFAULT;
+ }
+
+ return open_serial(path_name);
+ break;
+ }
+ case V3_VM_STOP: {
+ printk("Stopping VM\n");
+ stop_palacios_vm(guest);
+ break;
+ }
+ default:
+ printk("\tUnhandled\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int v3_vm_open(struct inode * inode, struct file * filp) {
+ struct v3_guest * guest = container_of(inode->i_cdev, struct v3_guest, cdev);
+ filp->private_data = guest;
+ return 0;
+}
+
+
+static ssize_t v3_vm_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
+
+ return 0;
+}
+
+
+static ssize_t v3_vm_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
+
+
+ return 0;
+}
+
+
+static struct file_operations v3_vm_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = v3_vm_ioctl,
+ .compat_ioctl = v3_vm_ioctl,
+ .open = v3_vm_open,
+ .read = v3_vm_read,
+ .write = v3_vm_write,
+};
+
+
+
+extern int vm_running;
+extern u32 pg_allocs;
+extern u32 pg_frees;
+extern u32 mallocs;
+extern u32 frees;
+
+
+int start_palacios_vm(void * arg) {
+ struct v3_guest * guest = (struct v3_guest *)arg;
+ int err;
+
+ lock_kernel();
+ daemonize(guest->name);
+// allow_signal(SIGKILL);
+ unlock_kernel();
+
+
+
+
+ guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
+
+ if (guest->v3_ctx == NULL) {
+ printk("palacios: failed to create vm\n");
+ return -1;
+ }
+
+ printk("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
+
+ cdev_init(&(guest->cdev), &v3_vm_fops);
+
+ guest->cdev.owner = THIS_MODULE;
+ guest->cdev.ops = &v3_vm_fops;
+
+
+ printk("Adding VM device\n");
+ err = cdev_add(&(guest->cdev), guest->vm_dev, 1);
+
+ if (err) {
+ printk("Fails to add cdev\n");
+ 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");
+ return -1;
+ }
+
+ complete(&(guest->thread_done));
+
+
+ printk("palacios: launching vm\n");
+
+ if (v3_start_vm(guest->v3_ctx, 0xffffffff) < 0) {
+ printk("palacios: launch of vm failed\n");
+ return -1;
+ }
+
+ complete(&(guest->thread_done));
+
+
+ printk("palacios: vm completed. returning.\n");
+
+ return 0;
+}
+
+
+
+
+int stop_palacios_vm(struct v3_guest * guest) {
+
+ v3_stop_vm(guest->v3_ctx);
+
+ wait_for_completion(&(guest->thread_done));
+
+ v3_free_vm(guest->v3_ctx);
+
+
+ return 0;
+}
--- /dev/null
+/*
+ * Palacios VM interface
+ * (c) Jack Lange, 2010
+ */
+
+#ifndef __PALACIOS_VM_H__
+#define __PALACIOS_VM_H__
+
+#include "palacios.h"
+
+int start_palacios_vm(void * arg);
+int stop_palacios_vm(struct v3_guest * guest);
+
+#endif
--- /dev/null
+/*
+ Palacios VNET interface
+ (c) Lei Xia, 2010
+ */
+#include <linux/spinlock.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+#include <asm/uaccess.h>
+#include <linux/inet.h>
+#include <linux/kthread.h>
+
+#include <linux/netdevice.h>
+#include <linux/ip.h>
+#include <linux/in.h>
+#include <linux/string.h>
+#include <linux/preempt.h>
+#include <linux/sched.h>
+#include <asm/msr.h>
+
+#include <palacios/vmm_vnet.h>
+#include "palacios-vnet.h"
+
+//#define DEBUG_VNET_BRIGE
+
+#define VNET_UDP_PORT 9000
+
+struct vnet_route {
+ struct v3_vnet_route route;
+
+ int route_idx;
+
+ struct list_head node;
+};
+
+
+struct vnet_link {
+ uint32_t dst_ip;
+ uint16_t dst_port;
+
+ struct socket * sock;
+ struct sockaddr_in sock_addr;
+
+ int link_idx;
+
+ struct list_head node;
+};
+
+struct palacios_vnet_state {
+ uint32_t num_routes;
+ uint32_t num_links;
+
+ struct list_head route_list;
+ struct list_head link_list;
+
+ struct socket * serv_sock;
+ struct sockaddr_in serv_addr;
+
+ /* The thread recving pkts from sockets. */
+ struct task_struct * serv_thread;
+ spinlock_t lock;
+
+ unsigned long pkt_sent, pkt_recv, pkt_drop, pkt_udp_recv, pkt_udp_send;
+};
+
+
+static struct palacios_vnet_state vnet_state;
+
+
+struct vnet_link * find_link_by_ip(uint32_t ip) {
+ struct vnet_link * link = NULL;
+
+ list_for_each_entry(link, &(vnet_state.link_list), node) {
+
+ if (link->dst_ip == ip) {
+ return link;
+ }
+ }
+
+ return NULL;
+}
+
+struct vnet_link * find_link_by_idx(int idx) {
+ struct vnet_link * link = NULL;
+
+ list_for_each_entry(link, &(vnet_state.link_list), node) {
+
+ if (link->link_idx == idx) {
+ return link;
+ }
+ }
+ return NULL;
+}
+
+struct vnet_route * find_route_by_idx(int idx) {
+ struct vnet_route * route = NULL;
+
+ list_for_each_entry(route, &(vnet_state.route_list), node) {
+
+ if (route->route_idx == idx) {
+ return route;
+ }
+ }
+
+ return NULL;
+}
+
+
+static int parse_mac_str(char * str, uint8_t * qual, uint8_t * mac) {
+ char * token;
+
+ printk("Parsing MAC (%s)\n", str);
+
+ if (strstr(str, "-")) {
+ token = strsep(&str, "-");
+
+ if (strnicmp("not", token, strlen("not")) == 0) {
+ *qual = MAC_NOT;
+ } else {
+ printk("Invalid MAC String token (%s)\n", token);
+ return -1;
+ }
+ }
+
+ if (!strstr(str, ":")) {
+ if (strnicmp("any", str, strlen("any")) == 0) {
+ printk("qual = any\n");
+ *qual = MAC_ANY;
+ } else if (strnicmp("none", str, strlen("none")) == 0) {
+ printk("qual = None\n");
+ *qual = MAC_NONE;
+ } else {
+ printk("Invalid MAC Qual token (%s)\n", str);
+ return -1;
+ }
+
+ } else {
+ int i = 0;
+
+ *qual = MAC_ADDR;
+
+ for (i = 0; i < 6; i++) {
+ token = strsep(&str, ":");
+ mac[i] = simple_strtol(token, &token, 16);
+ }
+ }
+
+ return 0;
+}
+
+static int parse_route_str(char * str, struct v3_vnet_route * route) {
+ char * token = NULL;
+ struct vnet_link *link = NULL;
+
+ // src MAC
+ token = strsep(&str, " ");
+
+ if (!token) {
+ return -1;
+ }
+
+ parse_mac_str(token, &(route->src_mac_qual), route->src_mac);
+
+ // dst MAC
+ token = strsep(&str, " ");
+
+ if (!token) {
+ return -1;
+ }
+
+ parse_mac_str(token, &(route->dst_mac_qual), route->dst_mac);
+
+ // dst LINK type
+ token = strsep(&str, " ");
+
+ if (!token) {
+ return -1;
+ }
+
+ if (strnicmp("interface", token, strlen("interface")) == 0) {
+ route->dst_type = LINK_INTERFACE;
+ printk("DST type = INTERFACE\n");
+ } else if (strnicmp("edge", token, strlen("edge")) == 0) {
+ route->dst_type = LINK_EDGE;
+ printk("DST type = EDGE\n");
+ } else {
+ printk("Invalid Destination Link Type (%s)\n", token);
+ return -1;
+ }
+
+
+ // dst link ID
+ token = strsep(&str, " ");
+
+ if (!token) {
+ return -1;
+ }
+
+ printk("dst link ID=%s\n", token);
+
+ // Figure out link ID here
+ if (route->dst_type == LINK_EDGE) {
+ uint32_t link_ip;
+
+
+ // Figure out Link Here
+ if (in4_pton(token, strlen(token), (uint8_t *)&(link_ip), '\0', NULL) != 1) {
+ printk("Invalid Dst IP address (%s)\n", token);
+ return -EFAULT;
+ }
+
+
+ printk("link_ip = %d\n", link_ip);
+ link = find_link_by_ip(link_ip);
+ if (link != NULL){
+ route->dst_id = link->link_idx;
+ }else{
+ printk("can not find dst link %s\n", token);
+ return -1;
+ }
+ } else {
+ printk("Unsupported dst link type\n");
+ return -1;
+ }
+
+ // src LINK
+ token = strsep(&str, " ");
+
+ printk("SRC type = %s\n", token);
+
+ if (!token) {
+ return -1;
+ }
+
+ if (strnicmp("interface", token, strlen("interface")) == 0) {
+ route->src_type = LINK_INTERFACE;
+ printk("SRC type = INTERFACE\n");
+ } else if (strnicmp("edge", token, strlen("edge")) == 0) {
+ route->src_type = LINK_EDGE;
+ printk("SRC type = EDGE\n");
+ } else if (strnicmp("any", token, strlen("any")) == 0) {
+ route->src_type = LINK_ANY;
+ printk("SRC type = ANY\n");
+ } else {
+ printk("Invalid Src link type (%s)\n", token);
+ return -1;
+ }
+
+
+ if (route->src_type == LINK_ANY) {
+ route->src_id = (uint32_t)-1;
+ } else if (route->src_type == LINK_EDGE) {
+ uint32_t src_ip;
+ token = strsep(&str, " ");
+
+ if (!token) {
+ return -1;
+ }
+
+ // Figure out Link Here
+ if (in4_pton(token, strlen(token), (uint8_t *)&(src_ip), '\0', NULL) != 1) {
+ printk("Invalid SRC IP address (%s)\n", token);
+ return -EFAULT;
+ }
+
+ link = find_link_by_ip(src_ip);
+ if (link != NULL){
+ route->src_id = link->link_idx;
+ }else{
+ printk("can not find src link %s\n", token);
+ return -1;
+ }
+ } else {
+ printk("Invalid link type\n");
+ return -1;
+ }
+
+
+ return 0;
+}
+
+
+
+
+static void * route_seq_start(struct seq_file * s, loff_t * pos) {
+ struct vnet_route * route_iter = NULL;
+ loff_t i = 0;
+
+
+ if (*pos >= vnet_state.num_routes) {
+ return NULL;
+ }
+
+ list_for_each_entry(route_iter, &(vnet_state.route_list), node) {
+
+ if (i == *pos) {
+ break;
+ }
+
+ i++;
+ }
+
+ return route_iter;
+}
+
+
+static void * link_seq_start(struct seq_file * s, loff_t * pos) {
+ struct vnet_link * link_iter = NULL;
+ loff_t i = 0;
+
+
+ if (*pos >= vnet_state.num_links) {
+ return NULL;
+ }
+
+ list_for_each_entry(link_iter, &(vnet_state.link_list), node) {
+
+ if (i == *pos) {
+ break;
+ }
+
+ i++;
+ }
+
+ return link_iter;
+}
+
+
+
+static void * route_seq_next(struct seq_file * s, void * v, loff_t * pos) {
+ struct vnet_route * route_iter = NULL;
+
+ route_iter = list_entry(((struct vnet_route *)v)->node.next, struct vnet_route, node);
+
+ // Check if the list has looped
+ if (&(route_iter->node) == &(vnet_state.route_list)) {
+ return NULL;
+ }
+
+ *pos += 1;
+
+ return route_iter;
+}
+
+
+static void * link_seq_next(struct seq_file * s, void * v, loff_t * pos) {
+ struct vnet_link * link_iter = NULL;
+
+
+ link_iter = list_entry(((struct vnet_link *)v)->node.next, struct vnet_link, node);
+
+ // Check if the list has looped
+ if (&(link_iter->node) == &(vnet_state.link_list)) {
+ return NULL;
+ }
+
+ *pos += 1;
+
+ return link_iter;
+}
+
+
+static void route_seq_stop(struct seq_file * s, void * v) {
+ printk("route_seq_stop\n");
+
+ return;
+}
+
+
+static void link_seq_stop(struct seq_file * s, void * v) {
+ printk("link_seq_stop\n");
+
+ return;
+}
+
+static int route_seq_show(struct seq_file * s, void * v) {
+ struct vnet_route * route_iter = v;
+ struct v3_vnet_route * route = &(route_iter->route);
+
+
+ seq_printf(s, "%d:\t", route_iter->route_idx);
+
+ switch (route->src_mac_qual) {
+ case MAC_ANY:
+ seq_printf(s, "any ");
+ break;
+ case MAC_NONE:
+ seq_printf(s, "none ");
+ break;
+ case MAC_NOT:
+ seq_printf(s, "not-%x:%x:%x:%x:%x:%x ",
+ route->src_mac[0], route->src_mac[1], route->src_mac[2],
+ route->src_mac[3], route->src_mac[4], route->src_mac[5]);
+ break;
+ default:
+ seq_printf(s, "%x:%x:%x:%x:%x:%x ",
+ route->src_mac[0], route->src_mac[1], route->src_mac[2],
+ route->src_mac[3], route->src_mac[4], route->src_mac[5]);
+ break;
+ }
+
+ switch (route->dst_mac_qual) {
+ case MAC_ANY:
+ seq_printf(s, "any ");
+ break;
+ case MAC_NONE:
+ seq_printf(s, "none ");
+ break;
+ case MAC_NOT:
+ seq_printf(s, "not-%x:%x:%x:%x:%x:%x ",
+ route->src_mac[0], route->src_mac[1], route->src_mac[2],
+ route->src_mac[3], route->src_mac[4], route->src_mac[5]);
+ break;
+ default:
+ seq_printf(s, "%x:%x:%x:%x:%x:%x ",
+ route->src_mac[0], route->src_mac[1], route->src_mac[2],
+ route->src_mac[3], route->src_mac[4], route->src_mac[5]);
+ break;
+ }
+
+
+ switch (route->dst_type) {
+ case LINK_EDGE: {
+ struct vnet_link * link = (struct vnet_link *)find_link_by_idx(route->dst_id);
+ seq_printf(s, "EDGE %pI4", &link->dst_ip);
+ break;
+ }
+ case LINK_INTERFACE: {
+ seq_printf(s, "INTERFACE ");
+ seq_printf(s, "%d ", route->dst_id);
+ break;
+ }
+ default:
+ seq_printf(s, "Invalid Dst Link Type (%d) ", route->dst_type);
+ break;
+ }
+
+
+
+
+
+ switch (route->src_type) {
+ case LINK_EDGE: {
+ struct vnet_link * link = (struct vnet_link *)find_link_by_idx(route->src_id);
+ seq_printf(s, "EDGE %pI4", &link->dst_ip);
+ break;
+ }
+ case LINK_INTERFACE: {
+ seq_printf(s, "INTERFACE %d", route->src_id);
+ break;
+ }
+ case LINK_ANY:
+ seq_printf(s, "ANY");
+ break;
+ default:
+ seq_printf(s, "Invalid Src Link Type (%d) ", route->src_type);
+ break;
+ }
+
+
+ seq_printf(s, "\n");
+
+ return 0;
+}
+
+
+static int link_seq_show(struct seq_file * s, void * v) {
+ struct vnet_link * link_iter = v;
+
+ seq_printf(s, "%d:\t%pI4\t%d\n",
+ link_iter->link_idx,
+ &link_iter->dst_ip,
+ link_iter->dst_port);
+
+ return 0;
+}
+
+
+static struct seq_operations route_seq_ops = {
+ .start = route_seq_start,
+ .next = route_seq_next,
+ .stop = route_seq_stop,
+ .show = route_seq_show
+};
+
+
+static struct seq_operations link_seq_ops = {
+ .start = link_seq_start,
+ .next = link_seq_next,
+ .stop = link_seq_stop,
+ .show = link_seq_show
+};
+
+
+static int route_open(struct inode * inode, struct file * file) {
+ return seq_open(file, &route_seq_ops);
+}
+
+
+static int link_open(struct inode * inode, struct file * file) {
+ return seq_open(file, &link_seq_ops);
+}
+
+static int inject_route(struct vnet_route * route) {
+ v3_vnet_add_route(route->route);
+
+ printk("Palacios-vnet: One route added to VNET core\n");
+
+ return 0;
+}
+
+static ssize_t
+route_write(struct file * file,
+ const char * buf,
+ size_t size,
+ loff_t * ppos) {
+ char route_buf[256];
+ char * buf_iter = NULL;
+ char * line_str = route_buf;
+ char * token = NULL;
+
+ if (size >= 256) {
+ return -EFAULT;
+ }
+
+ if (copy_from_user(route_buf, buf, size)) {
+ return -EFAULT;
+ }
+
+ printk("Route written: %s\n", route_buf);
+
+ while ((buf_iter = strsep(&line_str, "\r\n"))) {
+
+ token = strsep(&buf_iter, " ");
+ if (!token) {
+ return -EFAULT;
+ }
+
+ if (strnicmp("ADD", token, strlen("ADD")) == 0) {
+ struct vnet_route * new_route = NULL;
+ new_route = kmalloc(sizeof(struct vnet_route), GFP_KERNEL);
+
+ if (!new_route) {
+ return -ENOMEM;
+ }
+
+ memset(new_route, 0, sizeof(struct vnet_route));
+
+ if (parse_route_str(buf_iter, &(new_route->route)) == -1) {
+ kfree(new_route);
+ return -EFAULT;
+ }
+
+ if (inject_route(new_route) != 0) {
+ return -EFAULT;
+ }
+ } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
+ printk("I should delete the route here\n");
+ } else {
+ printk("Invalid Route command string\n");
+ }
+ }
+
+ return size;
+}
+
+
+static int create_link(struct vnet_link * link) {
+ int err;
+ unsigned long flags;
+
+ if ( (err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &link->sock)) < 0) {
+ printk("Could not create socket\n");
+ return -1;
+ }
+
+ memset(&link->sock_addr, 0, sizeof(struct sockaddr));
+
+ link->sock_addr.sin_family = AF_INET;
+ link->sock_addr.sin_addr.s_addr = link->dst_ip;
+ link->sock_addr.sin_port = htons(link->dst_port);
+
+ if ((err = link->sock->ops->connect(link->sock, (struct sockaddr *)&(link->sock_addr), sizeof(struct sockaddr), 0) < 0)) {
+ printk("Could not connect to remote host\n");
+ return -1;
+ }
+
+ // We use the file pointer because we are in the kernel
+ // This is only used to assigned File Descriptors for user space, so it is available here
+ // link->sock->file = link;
+
+ spin_lock_irqsave(&(vnet_state.lock), flags);
+ list_add(&(link->node), &(vnet_state.link_list));
+ link->link_idx = vnet_state.num_links++;
+ spin_unlock_irqrestore(&(vnet_state.lock), flags);
+
+ printk("VNET Bridge: Link created, ip %d, port: %d, idx: %d, link: %p\n",
+ link->dst_ip,
+ link->dst_port,
+ link->link_idx,
+ link);
+
+ return 0;
+}
+
+static ssize_t
+link_write(struct file * file, const char * buf, size_t size, loff_t * ppos) {
+ char link_buf[256];
+ char * link_iter = NULL;
+ char * line_str = link_buf;
+ char * token = NULL;
+
+ if (size >= 256) {
+ return -EFAULT;
+ }
+
+ if (copy_from_user(link_buf, buf, size)) {
+ return -EFAULT;
+ }
+
+ while ((link_iter = strsep(&line_str, "\r\n"))) {
+ printk("Link written: %s\n", link_buf);
+
+ token = strsep(&link_iter, " ");
+
+ if (!token) {
+ return -EFAULT;
+ }
+
+ if (strnicmp("ADD", token, strlen("ADD")) == 0) {
+ struct vnet_link * new_link = NULL;
+ char * ip_str = NULL;
+ uint32_t ip;
+
+ ip_str = strsep(&link_iter, " ");
+
+ if ((!ip_str) || (!link_iter)) {
+ printk("Missing fields in ADD Link command\n");
+ return -EFAULT;
+ }
+
+ if (in4_pton(ip_str, strlen(ip_str), (uint8_t *)&(ip), '\0', NULL) != 1) {
+ printk("Invalid Dst IP address (%s)\n", ip_str);
+ return -EFAULT;
+ }
+
+ new_link = kmalloc(sizeof(struct vnet_link), GFP_KERNEL);
+
+ if (!new_link) {
+ return -ENOMEM;
+ }
+
+ memset(new_link, 0, sizeof(struct vnet_link));
+
+ new_link->dst_ip = ip;
+ new_link->dst_port = simple_strtol(link_iter, &link_iter, 10);
+
+ if (create_link(new_link) != 0) {
+ printk("Could not create link\n");
+ kfree(new_link);
+ return -EFAULT;
+ }
+
+ } else if (strnicmp("DEL", token, strlen("DEL")) == 0) {
+ printk("Link deletion not supported\n");
+ } else {
+ printk("Invalid Link command string\n");
+ }
+ }
+
+ return size;
+}
+
+
+static struct file_operations route_fops = {
+ .owner = THIS_MODULE,
+ .open = route_open,
+ .read = seq_read,
+ .write = route_write,
+ .llseek = seq_lseek,
+ .release = seq_release
+};
+
+
+static struct file_operations link_fops = {
+ .owner = THIS_MODULE,
+ .open = link_open,
+ .read = seq_read,
+ .write = link_write,
+ .llseek = seq_lseek,
+ .release = seq_release
+};
+
+
+static int init_proc_files(void) {
+ struct proc_dir_entry * route_entry = NULL;
+ struct proc_dir_entry * link_entry = NULL;
+ struct proc_dir_entry * vnet_root = NULL;
+
+
+ vnet_root = proc_mkdir("vnet", NULL);
+ if (vnet_root == NULL) {
+ return -1;
+ }
+
+ route_entry = create_proc_entry("routes", 0, vnet_root);
+
+ if (route_entry == NULL) {
+ remove_proc_entry("vnet", NULL);
+ return -1;
+ }
+
+ route_entry->proc_fops = &route_fops;
+
+
+ link_entry = create_proc_entry("links", 0, vnet_root);
+
+ if (link_entry == NULL) {
+ remove_proc_entry("routes", vnet_root);
+ remove_proc_entry("vnet", NULL);
+ return -1;
+ }
+
+ link_entry->proc_fops = &link_fops;
+
+ return 0;
+
+}
+
+
+
+static int
+udp_send(struct socket * sock,
+ struct sockaddr_in * addr,
+ unsigned char * buf, int len) {
+ struct msghdr msg;
+ struct iovec iov;
+ mm_segment_t oldfs;
+ int size = 0;
+
+
+ if (sock->sk == NULL) {
+ return 0;
+ }
+
+ iov.iov_base = buf;
+ iov.iov_len = len;
+
+ msg.msg_flags = 0;
+ msg.msg_name = addr;
+ msg.msg_namelen = sizeof(struct sockaddr_in);
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ size = sock_sendmsg(sock, &msg, len);
+ set_fs(oldfs);
+
+ return size;
+}
+
+
+
+static int
+udp_recv(struct socket * sock,
+ struct sockaddr_in * addr,
+ unsigned char * buf, int len) {
+ struct msghdr msg;
+ struct iovec iov;
+ mm_segment_t oldfs;
+ int size = 0;
+
+ if (sock->sk == NULL) {
+ return 0;
+ }
+
+ iov.iov_base = buf;
+ iov.iov_len = len;
+
+ msg.msg_flags = 0;
+ msg.msg_name = addr;
+ msg.msg_namelen = sizeof(struct sockaddr_in);
+ msg.msg_control = NULL;
+ msg.msg_controllen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = NULL;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+ size = sock_recvmsg(sock, &msg, len, msg.msg_flags);
+
+ set_fs(oldfs);
+
+ return size;
+}
+
+//send packets from Network to VNET core
+static int
+send_to_palacios(unsigned char * buf,
+ int len,
+ int link_id){
+ struct v3_vnet_pkt pkt;
+ pkt.size = len;
+ pkt.src_type = LINK_EDGE;
+ pkt.src_id = link_id;
+ memcpy(pkt.header, buf, ETHERNET_HEADER_LEN);
+ pkt.data = buf;
+
+#ifdef DEBUG_VNET_BRIGE
+ {
+ printk("VNET Lnx Bridge: send pkt to VNET core (size: %d, src_id: %d, src_type: %d)\n",
+ pkt.size, pkt.src_id, pkt.src_type);
+
+ print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt.data, pkt.size, 0);
+ }
+#endif
+
+ return v3_vnet_send_pkt(&pkt, NULL);;
+}
+
+
+//send packet from VNET core to Network
+static int
+bridge_send_pkt(struct v3_vm_info * vm,
+ struct v3_vnet_pkt * pkt,
+ void * private_data) {
+ struct vnet_link * link;
+
+ #ifdef DEBUG_VNET_BRIGE
+ {
+ printk("VNET Lnx Host Bridge: packet received from VNET Core ... len: %d, pkt size: %d, link: %d\n",
+ len,
+ pkt->size,
+ pkt->dst_id);
+
+ print_hex_dump(NULL, "pkt_data: ", 0, 20, 20, pkt->data, pkt->size, 0);
+ }
+ #endif
+
+ vnet_state.pkt_recv ++;
+
+ link = find_link_by_idx(pkt->dst_id);
+ if (link != NULL) {
+ udp_send(link->sock, &(link->sock_addr), pkt->data, pkt->size);
+ vnet_state.pkt_udp_send ++;
+ } else {
+ printk("VNET Bridge Linux Host: wrong dst link, idx: %d, discards the packet\n", pkt->dst_id);
+ vnet_state.pkt_drop ++;
+ }
+
+ return 0;
+}
+
+
+static void
+poll_pkt(struct v3_vm_info * vm,
+ void * private_data) {
+
+
+}
+
+
+
+static int init_vnet_serv(void) {
+
+ if (sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &vnet_state.serv_sock) < 0) {
+ printk("Could not create socket\n");
+ return -1;
+ }
+
+ memset(&vnet_state.serv_addr, 0, sizeof(struct sockaddr));
+
+ vnet_state.serv_addr.sin_family = AF_INET;
+ vnet_state.serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ vnet_state.serv_addr.sin_port = htons(VNET_UDP_PORT);
+
+ if (vnet_state.serv_sock->ops->bind(vnet_state.serv_sock, (struct sockaddr *)&(vnet_state.serv_addr), sizeof(struct sockaddr)) < 0) {
+ printk("Could not bind VNET server socket to port %d\n", VNET_UDP_PORT);
+ return -1;
+ }
+
+ printk("VNET server bind to port: %d\n", VNET_UDP_PORT);
+
+ return 0;
+}
+
+static int vnet_server(void * arg) {
+ unsigned char pkt[ETHERNET_PACKET_LEN];
+ struct sockaddr_in pkt_addr;
+ struct vnet_link *link = NULL;
+ int len;
+ int link_id;
+
+ printk("Palacios VNET Bridge: UDP receiving server ..... \n");
+
+ while (!kthread_should_stop()) {
+
+ len = udp_recv(vnet_state.serv_sock, &pkt_addr, pkt, ETHERNET_PACKET_LEN);
+ if(len < 0) {
+ printk("Receive error: Could not get packet, error %d\n", len);
+ continue;
+ }
+
+ link = find_link_by_ip(ntohl(pkt_addr.sin_addr.s_addr));
+ if (link != NULL){
+ link_id= link->link_idx;
+ }
+ else {
+ link_id= 0;
+ }
+
+ vnet_state.pkt_udp_recv ++;
+
+ send_to_palacios(pkt, len, link_id);
+ }
+
+ return 0;
+}
+
+#if 0
+static int profiling(void *args) {
+ static unsigned long long last_time=0;
+ unsigned long long cur_time=0;
+ set_user_nice(current, MAX_PRIO-1);
+
+ while (!kthread_should_stop()) {
+ rdtscll(cur_time);
+ if((cur_time - last_time) > 50000000000) {
+ last_time = cur_time;
+ printk("Palacios Linux VNET Bridge - profiling: sent: %ld, rxed: %ld, dropped: %ld, upd send: %ld, udp recv: %ld\n",
+ vnet_state.pkt_sent,
+ vnet_state.pkt_recv,
+ vnet_state.pkt_drop,
+ vnet_state.pkt_udp_send,
+ vnet_state.pkt_udp_recv);
+ }
+ schedule();
+ }
+
+ return 0;
+}
+#endif
+
+int palacios_init_vnet(void) {
+ struct v3_vnet_bridge_ops bridge_ops;
+
+ memset(&vnet_state, 0, sizeof(struct palacios_vnet_state));
+
+ INIT_LIST_HEAD(&(vnet_state.link_list));
+ INIT_LIST_HEAD(&(vnet_state.route_list));
+ spin_lock_init(&(vnet_state.lock));
+
+ init_proc_files();
+ if(init_vnet_serv() < 0){
+ printk("Failure to initiate VNET server\n");
+ return -1;
+ }
+
+ vnet_state.serv_thread = kthread_run(vnet_server, NULL, "vnet-server");
+
+ //kthread_run(profiling, NULL, "Profiling");
+
+ bridge_ops.input = bridge_send_pkt;
+ bridge_ops.poll = poll_pkt;
+
+ v3_vnet_add_bridge(NULL, &bridge_ops, HOST_LNX_BRIDGE, NULL);
+
+ printk("Palacios VNET Linux Bridge initiated\n");
+
+ return 0;
+}
+
--- /dev/null
+/*
+ * Palacios VNET Linux Bridge
+ * (c) Lei Xia, 2010
+ */
+
+#ifndef __PALACIOS_VNET_BRIDGE_H__
+#define __PALACIOS_VNET_BRIDGE_H__
+
+#include <palacios/vmm_vnet.h>
+
+int palacios_init_vnet(void);
+
+#endif
+
--- /dev/null
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/spinlock.h>
+#include <linux/gfp.h>
+#include <linux/interrupt.h>
+#include <linux/linkage.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <asm/irq_vectors.h>
+#include <asm/io.h>
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <asm/uaccess.h>
+#include <linux/smp_lock.h>
+
+#include <palacios/vmm.h>
+#include <palacios/vmm_host_events.h>
+#include "palacios.h"
+
+
+
+
+#include "palacios-mm.h"
+
+
+u32 pg_allocs = 0;
+u32 pg_frees = 0;
+u32 mallocs = 0;
+u32 frees = 0;
+
+
+static struct v3_vm_info * irq_to_guest_map[256];
+
+
+extern unsigned int cpu_khz;
+
+
+/**
+ * Prints a message to the console.
+ */
+static void palacios_print(const char * fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vprintk(fmt, ap);
+ va_end(ap);
+
+ return;
+}
+
+
+
+/*
+ * Allocates a contiguous region of pages of the requested size.
+ * Returns the physical address of the first page in the region.
+ */
+static void * palacios_allocate_pages(int num_pages, unsigned int alignment) {
+ void * pg_addr = NULL;
+
+ pg_addr = (void *)alloc_palacios_pgs(num_pages, alignment);
+ pg_allocs += num_pages;
+
+ return pg_addr;
+}
+
+
+/**
+ * Frees a page previously allocated via palacios_allocate_page().
+ * Note that palacios_allocate_page() can allocate multiple pages with
+ * a single call while palacios_free_page() only frees a single page.
+ */
+
+static void palacios_free_pages(void * page_paddr, int num_pages) {
+ pg_frees += num_pages;
+ free_palacios_pgs((uintptr_t)page_paddr, num_pages);
+}
+
+
+/**
+ * Allocates 'size' bytes of kernel memory.
+ * Returns the kernel virtual address of the memory allocated.
+ */
+static void *
+palacios_alloc(unsigned int size) {
+ void * addr = NULL;
+
+ addr = kmalloc(size, GFP_KERNEL);
+ mallocs++;
+
+ return addr;
+}
+
+/**
+ * Frees memory that was previously allocated by palacios_alloc().
+ */
+static void
+palacios_free(
+ void * addr
+)
+{
+ frees++;
+ kfree(addr);
+ return;
+}
+
+/**
+ * Converts a kernel virtual address to the corresponding physical address.
+ */
+static void *
+palacios_vaddr_to_paddr(
+ void * vaddr
+)
+{
+ return (void*) __pa(vaddr);
+
+}
+
+/**
+ * Converts a physical address to the corresponding kernel virtual address.
+ */
+static void *
+palacios_paddr_to_vaddr(
+ void * paddr
+)
+{
+ return __va(paddr);
+}
+
+/**
+ * Runs a function on the specified CPU.
+ */
+
+// For now, do call only on local CPU
+static void
+palacios_xcall(
+ int cpu_id,
+ void (*fn)(void *arg),
+ void * arg
+)
+{
+ printk("palacios_xcall: Doing 'xcall' to local cpu\n");
+ fn(arg);
+ return;
+}
+
+struct lnx_thread_arg {
+ int (*fn)(void * arg);
+ void * arg;
+ char * name;
+};
+
+static int lnx_thread_target(void * arg) {
+ struct lnx_thread_arg * thread_info = (struct lnx_thread_arg *)arg;
+
+ /*
+ lock_kernel();
+ printk("Daemonizing new Palacios thread (name=%s)\n", thread_info->name);
+
+ daemonize(thread_info->name);
+ unlock_kernel();
+ allow_signal(SIGKILL);
+ */
+
+
+ thread_info->fn(thread_info->arg);
+
+ kfree(thread_info);
+ // handle cleanup
+
+ return 0;
+}
+
+/**
+ * Creates a kernel thread.
+ */
+static void
+palacios_start_kernel_thread(
+ int (*fn) (void * arg),
+ void * arg,
+ char * thread_name) {
+
+ struct lnx_thread_arg * thread_info = kmalloc(sizeof(struct lnx_thread_arg), GFP_KERNEL);
+
+ thread_info->fn = fn;
+ thread_info->arg = arg;
+ thread_info->name = thread_name;
+
+ kthread_run( lnx_thread_target, thread_info, thread_name );
+ return;
+}
+
+
+/**
+ * Starts a kernel thread on the specified CPU.
+ */
+static void *
+palacios_start_thread_on_cpu(int cpu_id,
+ int (*fn)(void * arg),
+ void * arg,
+ char * thread_name ) {
+ struct task_struct * thread = NULL;
+ struct lnx_thread_arg * thread_info = kmalloc(sizeof(struct lnx_thread_arg), GFP_KERNEL);
+
+ thread_info->fn = fn;
+ thread_info->arg = arg;
+ thread_info->name = thread_name;
+
+ thread = kthread_run( lnx_thread_target, thread_info, thread_name );
+
+ if (IS_ERR(thread)) {
+ printk("Palacios error creating thread: %s\n", thread_name);
+ return NULL;
+ }
+
+ return thread;
+}
+
+/**
+ * Returns the CPU ID that the caller is running on.
+ */
+static unsigned int
+palacios_get_cpu(void)
+{
+#if 1
+ return 0;
+ // return smp_processor_id();
+ // id = get_cpu(); put_cpu(id);
+ // return this_cpu;
+#else
+ struct cpumask mask;
+ unsigned int set;
+
+ if(sched_getaffinity(0,&mask)<0){
+ panic("sched_getaffinity failed");
+ return -1;
+ }
+ set = cpumask_first(&mask);
+ printk("***mask.bits: %d",set);
+ return set;
+#endif
+}
+
+/**
+ * Interrupts the physical CPU corresponding to the specified logical guest cpu.
+ *
+ * NOTE:
+ * This is dependent on the implementation of xcall_reschedule(). Currently
+ * xcall_reschedule does not explicitly call schedule() on the destination CPU,
+ * but instead relies on the return to user space to handle it. Because
+ * palacios is a kernel thread schedule will not be called, which is correct.
+ * If it ever changes to induce side effects, we'll need to figure something
+ * else out...
+ */
+static void
+palacios_interrupt_cpu(
+ struct v3_vm_info * vm,
+ int cpu_id,
+ int vector
+)
+{
+ // panic("palacios_interrupt_cpu");
+ // printk("Faking interruption of target CPU by not doing anything since there is only one CPU\n");
+ return;
+}
+
+/**
+ * Dispatches an interrupt to Palacios for handling.
+ */
+static void
+palacios_dispatch_interrupt( int vector, void * dev, struct pt_regs * regs ) {
+ struct v3_interrupt intr = {
+ .irq = vector,
+ .error = regs->orig_ax,
+ .should_ack = 1,
+ };
+
+ if (irq_to_guest_map[vector]) {
+ v3_deliver_irq(irq_to_guest_map[vector], &intr);
+ }
+
+}
+
+/**
+ * Instructs the kernel to forward the specified IRQ to Palacios.
+ */
+static int
+palacios_hook_interrupt(struct v3_vm_info * vm,
+ unsigned int vector ) {
+ printk("hooking vector %d\n", vector);
+
+ if (irq_to_guest_map[vector]) {
+ printk(KERN_WARNING
+ "%s: Interrupt vector %u is already hooked.\n",
+ __func__, vector);
+ return -1;
+ }
+
+ printk(KERN_DEBUG
+ "%s: Hooking interrupt vector %u to vm %p.\n",
+ __func__, vector, vm);
+
+ irq_to_guest_map[vector] = vm;
+
+ /*
+ * NOTE: Normally PCI devices are supposed to be level sensitive,
+ * but we need them to be edge sensitive so that they are
+ * properly latched by Palacios. Leaving them as level
+ * sensitive would lead to an interrupt storm.
+ */
+ //ioapic_set_trigger_for_vector(vector, ioapic_edge_sensitive);
+
+ //set_idtvec_handler(vector, palacios_dispatch_interrupt);
+ if (vector < 32) {
+ panic("unexpected vector for hooking\n");
+ } else {
+ int device_id = 0;
+
+ int flag = 0;
+ int error;
+
+ printk("hooking vector: %d\n", vector);
+
+ if (vector == 32) {
+ flag = IRQF_TIMER;
+ } else {
+ flag = IRQF_SHARED;
+ }
+
+ error = request_irq((vector - 32),
+ (void *)palacios_dispatch_interrupt,
+ flag,
+ "interrupt_for_palacios",
+ &device_id);
+
+ if (error) {
+ printk("error code for request_irq is %d\n", error);
+ panic("request vector %d failed",vector);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Acknowledges an interrupt.
+ */
+static int
+palacios_ack_interrupt(
+ int vector
+)
+{
+ ack_APIC_irq();
+ printk("Pretending to ack interrupt, vector=%d\n",vector);
+ return 0;
+}
+
+/**
+ * Returns the CPU frequency in kilohertz.
+ */
+static unsigned int
+palacios_get_cpu_khz(void)
+{
+ printk("cpu_khz is %u\n",cpu_khz);
+ if (cpu_khz==0) {
+ printk("faking cpu_khz to 1000000\n");
+ return 1000000;
+ } else {
+ return cpu_khz;
+ }
+ //return 1000000;
+}
+
+/**
+ * Yield the CPU so other host OS tasks can run.
+ */
+static void
+palacios_yield_cpu(void)
+{
+ schedule();
+ return;
+}
+
+
+
+/**
+ * Allocates a mutex.
+ * Returns NULL on failure.
+ */
+static void *
+palacios_mutex_alloc(void)
+{
+ spinlock_t *lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+ if (lock)
+ spin_lock_init(lock);
+ return lock;
+}
+
+/**
+ * Frees a mutex.
+ */
+static void
+palacios_mutex_free(
+ void * mutex
+)
+{
+ kfree(mutex);
+}
+
+/**
+ * Locks a mutex.
+ */
+static void
+palacios_mutex_lock(
+ void * mutex,
+ int must_spin
+)
+{
+ spin_lock((spinlock_t*)mutex);
+}
+
+/**
+ * Unlocks a mutex.
+ */
+static void
+palacios_mutex_unlock(
+ void * mutex
+)
+{
+ spin_unlock((spinlock_t*)mutex);
+}
+
+/**
+ * Structure used by the Palacios hypervisor to interface with the host kernel.
+ */
+static struct v3_os_hooks palacios_os_hooks = {
+ .print = palacios_print,
+ .allocate_pages = palacios_allocate_pages,
+ .free_pages = palacios_free_pages,
+ .malloc = palacios_alloc,
+ .free = palacios_free,
+ .vaddr_to_paddr = palacios_vaddr_to_paddr,
+ .paddr_to_vaddr = palacios_paddr_to_vaddr,
+ .hook_interrupt = palacios_hook_interrupt,
+ .ack_irq = palacios_ack_interrupt,
+ .get_cpu_khz = palacios_get_cpu_khz,
+ .start_kernel_thread = palacios_start_kernel_thread,
+ .yield_cpu = palacios_yield_cpu,
+ .mutex_alloc = palacios_mutex_alloc,
+ .mutex_free = palacios_mutex_free,
+ .mutex_lock = palacios_mutex_lock,
+ .mutex_unlock = palacios_mutex_unlock,
+ .get_cpu = palacios_get_cpu,
+ .interrupt_cpu = palacios_interrupt_cpu,
+ .call_on_cpu = palacios_xcall,
+ .start_thread_on_cpu = palacios_start_thread_on_cpu,
+};
+
+
+
+
+int palacios_vmm_init( void )
+{
+
+ memset(irq_to_guest_map, 0, sizeof(struct v3_vm_info *) * 256);
+
+ printk("palacios_init starting - calling init_v3\n");
+
+ Init_V3(&palacios_os_hooks, 1);
+
+
+ return 0;
+
+}
+
+
+int palacios_vmm_exit( void ) {
+
+ Shutdown_V3();
+
+ return 0;
+}
--- /dev/null
+#ifndef _PALACIOS_H
+#define _PALACIOS_H
+
+#include <linux/cdev.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+
+#include "palacios-console.h"
+
+/* Global Control IOCTLs */
+#define V3_START_GUEST 10
+#define V3_ADD_MEMORY 50
+
+/* VM Specific IOCTLs */
+#define V3_VM_CONSOLE_CONNECT 20
+#define V3_VM_SERIAL_CONNECT 21
+#define V3_VM_STOP 22
+
+struct v3_guest_img {
+ unsigned long long size;
+ void * guest_data;
+ char name[128];
+};
+
+struct v3_mem_region {
+ unsigned long long base_addr;
+ unsigned long long num_pages;
+};
+
+
+
+struct v3_guest {
+ void * v3_ctx;
+
+ void * img;
+ u32 img_size;
+
+ char name[128];
+
+ struct list_head files;
+ struct list_head streams;
+ struct list_head sockets;
+
+ struct palacios_console console;
+
+ struct completion thread_done;
+
+ dev_t vm_dev;
+ struct cdev cdev;
+};
+
+// For now MAX_VMS must be a multiple of 8
+// This is due to the minor number bitmap
+#define MAX_VMS 32
+
+
+
+
+
+extern void send_key_to_palacios(unsigned char status, unsigned char scan_code);
+
+
+int palacios_vmm_init( void );
+int palacios_vmm_exit( void );
+
+
+
+#endif