Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


moved linux module to main Palacios tree
Jack Lange [Thu, 10 Mar 2011 19:28:33 +0000 (13:28 -0600)]
27 files changed:
linux_module/Makefile [new file with mode: 0644]
linux_module/link.cmd [new file with mode: 0644]
linux_module/palacios-console.c [new file with mode: 0644]
linux_module/palacios-console.h [new file with mode: 0644]
linux_module/palacios-dev.c [new file with mode: 0644]
linux_module/palacios-file.c [new file with mode: 0644]
linux_module/palacios-file.h [new file with mode: 0644]
linux_module/palacios-mm.c [new file with mode: 0644]
linux_module/palacios-mm.h [new file with mode: 0644]
linux_module/palacios-packet.c [new file with mode: 0644]
linux_module/palacios-packet.h [new file with mode: 0644]
linux_module/palacios-queue.c [new file with mode: 0644]
linux_module/palacios-queue.h [new file with mode: 0644]
linux_module/palacios-ringbuf.h [new file with mode: 0644]
linux_module/palacios-ringbuffer.c [new file with mode: 0644]
linux_module/palacios-ringbuffer.h [new file with mode: 0644]
linux_module/palacios-serial.c [new file with mode: 0644]
linux_module/palacios-serial.h [new file with mode: 0644]
linux_module/palacios-socket.c [new file with mode: 0644]
linux_module/palacios-stream.c [new file with mode: 0644]
linux_module/palacios-stream.h [new file with mode: 0644]
linux_module/palacios-vm.c [new file with mode: 0644]
linux_module/palacios-vm.h [new file with mode: 0644]
linux_module/palacios-vnet.c [new file with mode: 0644]
linux_module/palacios-vnet.h [new file with mode: 0644]
linux_module/palacios.c [new file with mode: 0644]
linux_module/palacios.h [new file with mode: 0644]

diff --git a/linux_module/Makefile b/linux_module/Makefile
new file mode 100644 (file)
index 0000000..55eb199
--- /dev/null
@@ -0,0 +1,33 @@
+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
+
diff --git a/linux_module/link.cmd b/linux_module/link.cmd
new file mode 100644 (file)
index 0000000..6c014d8
--- /dev/null
@@ -0,0 +1,33 @@
+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 = .;
+
+       }
+}
+
diff --git a/linux_module/palacios-console.c b/linux_module/palacios-console.c
new file mode 100644 (file)
index 0000000..cc6d80e
--- /dev/null
@@ -0,0 +1,376 @@
+/* 
+ * 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;
+}
diff --git a/linux_module/palacios-console.h b/linux_module/palacios-console.h
new file mode 100644 (file)
index 0000000..9e443e5
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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
diff --git a/linux_module/palacios-dev.c b/linux_module/palacios-dev.c
new file mode 100644 (file)
index 0000000..585e807
--- /dev/null
@@ -0,0 +1,269 @@
+/* 
+   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);
diff --git a/linux_module/palacios-file.c b/linux_module/palacios-file.c
new file mode 100644 (file)
index 0000000..d26fcb2
--- /dev/null
@@ -0,0 +1,158 @@
+/* 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;
+}
diff --git a/linux_module/palacios-file.h b/linux_module/palacios-file.h
new file mode 100644 (file)
index 0000000..7e2180c
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __PALACIOS_FILE_H__
+#define __PALACISO_FILE_H__
+
+int palacios_file_init(void);
+
+#endif
diff --git a/linux_module/palacios-mm.c b/linux_module/palacios-mm.c
new file mode 100644 (file)
index 0000000..a6505e6
--- /dev/null
@@ -0,0 +1,194 @@
+/* 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;
+}
diff --git a/linux_module/palacios-mm.h b/linux_module/palacios-mm.h
new file mode 100644 (file)
index 0000000..940467c
--- /dev/null
@@ -0,0 +1,21 @@
+/* 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
diff --git a/linux_module/palacios-packet.c b/linux_module/palacios-packet.c
new file mode 100644 (file)
index 0000000..f6f4c2c
--- /dev/null
@@ -0,0 +1,204 @@
+/* 
+ * 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;
+}
+
diff --git a/linux_module/palacios-packet.h b/linux_module/palacios-packet.h
new file mode 100644 (file)
index 0000000..476f473
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * 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
diff --git a/linux_module/palacios-queue.c b/linux_module/palacios-queue.c
new file mode 100644 (file)
index 0000000..3e0249b
--- /dev/null
@@ -0,0 +1,81 @@
+/* 
+ * 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;
+}
diff --git a/linux_module/palacios-queue.h b/linux_module/palacios-queue.h
new file mode 100644 (file)
index 0000000..f35f05e
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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
diff --git a/linux_module/palacios-ringbuf.h b/linux_module/palacios-ringbuf.h
new file mode 100644 (file)
index 0000000..aca8ba8
--- /dev/null
@@ -0,0 +1,14 @@
+/* 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
diff --git a/linux_module/palacios-ringbuffer.c b/linux_module/palacios-ringbuffer.c
new file mode 100644 (file)
index 0000000..2ab5b50
--- /dev/null
@@ -0,0 +1,178 @@
+/* 
+ * 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
diff --git a/linux_module/palacios-ringbuffer.h b/linux_module/palacios-ringbuffer.h
new file mode 100644 (file)
index 0000000..eb39025
--- /dev/null
@@ -0,0 +1,26 @@
+/* 
+ * 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
diff --git a/linux_module/palacios-serial.c b/linux_module/palacios-serial.c
new file mode 100644 (file)
index 0000000..355f4d4
--- /dev/null
@@ -0,0 +1,132 @@
+/* 
+ * 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;
+}
diff --git a/linux_module/palacios-serial.h b/linux_module/palacios-serial.h
new file mode 100644 (file)
index 0000000..e9fa8a0
--- /dev/null
@@ -0,0 +1,11 @@
+/*
+ * Palacios VM Stream Serial interface
+ * (c) Jack Lange, 2010
+ */
+
+#ifndef __PALACIOS_SERIAL_H__
+#define __PALACIOS_SERIAL_H__
+
+int open_serial(char * name);
+
+#endif
diff --git a/linux_module/palacios-socket.c b/linux_module/palacios-socket.c
new file mode 100644 (file)
index 0000000..d76c5c6
--- /dev/null
@@ -0,0 +1,438 @@
+/*
+ * 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;
+}
diff --git a/linux_module/palacios-stream.c b/linux_module/palacios-stream.c
new file mode 100644 (file)
index 0000000..815a151
--- /dev/null
@@ -0,0 +1,122 @@
+
+/* 
+ * 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);
+}
+
+
diff --git a/linux_module/palacios-stream.h b/linux_module/palacios-stream.h
new file mode 100644 (file)
index 0000000..7e9279f
--- /dev/null
@@ -0,0 +1,37 @@
+/* 
+ * 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
+
diff --git a/linux_module/palacios-vm.c b/linux_module/palacios-vm.c
new file mode 100644 (file)
index 0000000..cd3ba2c
--- /dev/null
@@ -0,0 +1,177 @@
+/* 
+ * 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;
+}
diff --git a/linux_module/palacios-vm.h b/linux_module/palacios-vm.h
new file mode 100644 (file)
index 0000000..e0c5f74
--- /dev/null
@@ -0,0 +1,14 @@
+/* 
+ * 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
diff --git a/linux_module/palacios-vnet.c b/linux_module/palacios-vnet.c
new file mode 100644 (file)
index 0000000..ad51ee5
--- /dev/null
@@ -0,0 +1,976 @@
+/* 
+   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;
+}
+
diff --git a/linux_module/palacios-vnet.h b/linux_module/palacios-vnet.h
new file mode 100644 (file)
index 0000000..98f8dce
--- /dev/null
@@ -0,0 +1,14 @@
+/*
+ * 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
+
diff --git a/linux_module/palacios.c b/linux_module/palacios.c
new file mode 100644 (file)
index 0000000..7a3238e
--- /dev/null
@@ -0,0 +1,482 @@
+#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;
+}
diff --git a/linux_module/palacios.h b/linux_module/palacios.h
new file mode 100644 (file)
index 0000000..3ee850a
--- /dev/null
@@ -0,0 +1,68 @@
+#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