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.


Expose VM reset capability to Linux and Linux user
[palacios.git] / linux_module / vm.c
index da9b460..440ff69 100644 (file)
 #include <linux/poll.h>
 #include <linux/anon_inodes.h>
 #include <linux/sched.h>
-#include <linux/vmalloc.h>
 #include <linux/file.h>
 #include <linux/spinlock.h>
 #include <linux/rbtree.h>
+#include <linux/module.h>
 
 #include <palacios/vmm.h>
+#include <palacios/vmm_host_events.h>
 
 #include "palacios.h"
 #include "vm.h"
@@ -68,10 +69,10 @@ int add_guest_ctrl(struct v3_guest * guest, unsigned int cmd,
                                  unsigned int cmd, unsigned long arg, 
                                  void * priv_data),
                   void * priv_data) {
-    struct vm_ctrl * ctrl = kmalloc(sizeof(struct vm_ctrl), GFP_KERNEL);
+    struct vm_ctrl * ctrl = palacios_alloc(sizeof(struct vm_ctrl));
 
     if (ctrl == NULL) {
-       printk("Error: Could not allocate vm ctrl %d\n", cmd);
+       WARNING("Error: Could not allocate vm ctrl %d\n", cmd);
        return -1;
     }
 
@@ -80,8 +81,8 @@ int add_guest_ctrl(struct v3_guest * guest, unsigned int cmd,
     ctrl->priv_data = priv_data;
 
     if (__insert_ctrl(guest, ctrl) != NULL) {
-       printk("Could not insert guest ctrl %d\n", cmd);
-       kfree(ctrl);
+       WARNING("Could not insert guest ctrl %d\n", cmd);
+       palacios_free(ctrl);
        return -1;
     }
     
@@ -91,6 +92,8 @@ int add_guest_ctrl(struct v3_guest * guest, unsigned int cmd,
 }
 
 
+
+
 static struct vm_ctrl * get_ctrl(struct v3_guest * guest, unsigned int cmd) {
     struct rb_node * n = guest->vm_ctrls.rb_node;
     struct vm_ctrl * ctrl = NULL;
@@ -110,6 +113,35 @@ static struct vm_ctrl * get_ctrl(struct v3_guest * guest, unsigned int cmd) {
     return NULL;
 }
 
+int remove_guest_ctrl(struct v3_guest * guest, unsigned int cmd) {
+    struct vm_ctrl * ctrl = get_ctrl(guest, cmd);
+
+    if (ctrl == NULL) {
+       INFO("Could not find control (%d) to remove\n", cmd);
+       return -1;
+    }
+
+    rb_erase(&(ctrl->tree_node), &(guest->vm_ctrls));
+
+    palacios_free(ctrl);
+
+    return 0;
+}
+
+static void free_guest_ctrls(struct v3_guest * guest) {
+    struct rb_node * node = rb_first(&(guest->vm_ctrls));
+    struct vm_ctrl * ctrl = NULL;
+
+    while (node) {
+       ctrl = rb_entry(node, struct vm_ctrl, tree_node);
+
+       node = rb_next(node);
+       
+       WARNING("Cleaning up guest ctrl that was not removed explicitly (%d)\n", ctrl->cmd);
+
+       palacios_free(ctrl);
+    }
+}
 
 
 
@@ -124,24 +156,24 @@ static long v3_vm_ioctl(struct file * filp,
 
     struct v3_guest * guest = filp->private_data;
 
-    printk("V3 IOCTL %d\n", ioctl);
+    DEBUG("V3 IOCTL %d\n", ioctl);
 
     switch (ioctl) {
        case V3_VM_LAUNCH: {
-           printk("palacios: launching vm\n");
+           NOTICE("palacios: launching vm\n");
 
            if (v3_start_vm(guest->v3_ctx, (0x1 << num_online_cpus()) - 1) < 0) { 
-               printk("palacios: launch of vm failed\n");
+               WARNING("palacios: launch of vm failed\n");
                return -1;
            }
            
            break;
        }
        case V3_VM_STOP: {
-           printk("Stopping VM (%s) (%p)\n", guest->name, guest);
+           NOTICE("Stopping VM (%s) (%p)\n", guest->name, guest);
 
            if (irqs_disabled()) {
-               printk("WHAT!!?? IRQs are disabled??\n");
+               ERROR("WHAT!!?? IRQs are disabled??\n");
                break;
            }
 
@@ -149,20 +181,52 @@ static long v3_vm_ioctl(struct file * filp,
            break;
        }
        case V3_VM_PAUSE: {
-           printk("Pausing VM (%s)\n", guest->name);
+           NOTICE("Pausing VM (%s)\n", guest->name);
            v3_pause_vm(guest->v3_ctx);
            break;
        }
        case V3_VM_CONTINUE: {
-           printk("Continuing VM (%s)\n", guest->name);
+           NOTICE("Continuing VM (%s)\n", guest->name);
            v3_continue_vm(guest->v3_ctx);
            break;
        }
        case V3_VM_SIMULATE: {
-           printk("Simulating VM (%s) for %lu msecs\n", guest->name, arg);
+           NOTICE("Simulating VM (%s) for %lu msecs\n", guest->name, arg);
            v3_simulate_vm(guest->v3_ctx, arg);
            break;
        }
+       case V3_VM_RESET: {
+           struct v3_reset_cmd r;
+           void __user * argp = (void __user *)arg;
+           v3_vm_reset_type t;
+           uint32_t core_range[2];
+
+           if (copy_from_user(&r, argp, sizeof(struct v3_reset_cmd))) {
+               WARNING("Copy from user error getting reset info\n");
+               return -EFAULT;
+           }
+           
+           if (r.type==V3_RESET_VM_ALL) { 
+               t=V3_VM_RESET_ALL;
+           } else if (r.type==V3_RESET_VM_HRT) {
+               t=V3_VM_RESET_HRT;
+           } else if (r.type==V3_RESET_VM_ROS) {
+               t=V3_VM_RESET_ROS;
+           } else if (r.type==V3_RESET_VM_CORE_RANGE){
+               t=V3_VM_RESET_CORE_RANGE;
+               core_range[0]=r.first_core;
+               core_range[1]=r.first_core+r.num_cores-1;
+           } else {
+               ERROR("Unknown reset type %d requested\n",r.type);
+               return -EFAULT;
+           }
+           
+           if (v3_reset_vm_extended(guest->v3_ctx, t, core_range) == -1) {
+               WARNING("Error reseting VM\n");
+               return -EFAULT;
+           }
+           break;
+       }
 
 
 #ifdef V3_CONFIG_CHECKPOINT
@@ -173,14 +237,14 @@ static long v3_vm_ioctl(struct file * filp,
            memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
 
            if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
-               printk("Copy from user error getting checkpoint info\n");
+               WARNING("Copy from user error getting checkpoint info\n");
                return -EFAULT;
            }
            
-           printk("Saving Guest to %s:%s\n", chkpt.store, chkpt.url);
+           NOTICE("Saving Guest to %s:%s\n", chkpt.store, chkpt.url);
 
-           if (v3_save_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
-               printk("Error checkpointing VM state\n");
+           if (v3_save_vm(guest->v3_ctx, chkpt.store, chkpt.url, chkpt.opts) == -1) {
+               WARNING("Error checkpointing VM state\n");
                return -EFAULT;
            }
            
@@ -193,20 +257,91 @@ static long v3_vm_ioctl(struct file * filp,
            memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
 
            if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
-               printk("Copy from user error getting checkpoint info\n");
+               WARNING("Copy from user error getting checkpoint info\n");
+               return -EFAULT;
+           }
+           
+           NOTICE("Loading Guest from %s:%s\n", chkpt.store, chkpt.url);
+
+           if (v3_load_vm(guest->v3_ctx, chkpt.store, chkpt.url, chkpt.opts) == -1) {
+               WARNING("Error Loading VM state\n");
+               return -EFAULT;
+           }
+           
+           break;
+       }
+#endif
+
+#ifdef V3_CONFIG_LIVE_MIGRATION  
+       case V3_VM_SEND: {
+           struct v3_chkpt_info chkpt_info;
+           void __user * argp = (void __user *)arg;
+           
+           memset(&chkpt_info,0, sizeof(struct v3_chkpt_info));
+           
+           if(copy_from_user(&chkpt_info, argp, sizeof(struct v3_chkpt_info))){
+               WARNING("Copy from user error getting checkpoint info\n");
+               return -EFAULT;
+           }
+           
+           
+           NOTICE("Sending (live-migrating) Guest to %s:%s\n",chkpt_info.store, chkpt_info.url); 
+           
+           if (v3_send_vm(guest->v3_ctx, chkpt_info.store, chkpt_info.url, chkpt_info.opts) == -1) {
+               WARNING("Error sending VM\n");
                return -EFAULT;
            }
            
-           printk("Loading Guest to %s:%s\n", chkpt.store, chkpt.url);
+           break;
+       }
 
-           if (v3_load_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
-               printk("Error Loading VM state\n");
+       case V3_VM_RECEIVE: {
+           struct v3_chkpt_info chkpt_info;
+           void __user * argp = (void __user *)arg;
+           
+           memset(&chkpt_info,0, sizeof(struct v3_chkpt_info));
+
+           if(copy_from_user(&chkpt_info, argp, sizeof(struct v3_chkpt_info))){
+               WARNING("Copy from user error getting checkpoint info\n");
+               return -EFAULT;
+           }
+           
+           
+           NOTICE("Receiving (live-migrating) Guest to %s:%s\n",chkpt_info.store, chkpt_info.url);
+           
+           if (v3_receive_vm(guest->v3_ctx, chkpt_info.store, chkpt_info.url, chkpt_info.opts) == -1) {
+               WARNING("Error receiving VM\n");
                return -EFAULT;
            }
            
            break;
        }
 #endif
+
+       case V3_VM_DEBUG: {
+           struct v3_debug_cmd cmd;
+           struct v3_debug_event evt;
+           void __user * argp = (void __user *)arg;        
+
+           memset(&cmd, 0, sizeof(struct v3_debug_cmd));
+           
+           if (copy_from_user(&cmd, argp, sizeof(struct v3_debug_cmd))) {
+               ERROR("Error: Could not copy debug command from user space\n");
+               return -EFAULT;
+           }
+
+           evt.core_id = cmd.core;
+           evt.cmd = cmd.cmd;
+
+           INFO("Debugging VM\n");
+
+           if (v3_deliver_debug_event(guest->v3_ctx, &evt) == -1) {
+               ERROR("Error could not deliver debug cmd\n");
+               return -EFAULT;
+           }
+
+           break;
+       }
        case V3_VM_MOVE_CORE: {
            struct v3_core_move_cmd cmd;
            void __user * argp = (void __user *)arg;
@@ -214,13 +349,36 @@ static long v3_vm_ioctl(struct file * filp,
            memset(&cmd, 0, sizeof(struct v3_core_move_cmd));
            
            if (copy_from_user(&cmd, argp, sizeof(struct v3_core_move_cmd))) {
-               printk("copy from user error getting migrate command...\n");
+               WARNING("copy from user error getting migrate core command...\n");
+               return -EFAULT;
+           }
+       
+           INFO("moving guest %s vcore %d to CPU %d\n", guest->name, cmd.vcore_id, cmd.pcore_id);
+
+           if (v3_move_vm_core(guest->v3_ctx, cmd.vcore_id, cmd.pcore_id)) { 
+               ERROR("Could not move core\n");
+               return -EFAULT;
+           }
+
+           break;
+       }
+       case V3_VM_MOVE_MEM: {
+           struct v3_mem_move_cmd cmd;
+           void __user * argp = (void __user *)arg;
+
+           memset(&cmd, 0, sizeof(struct v3_mem_move_cmd));
+           
+           if (copy_from_user(&cmd, argp, sizeof(struct v3_mem_move_cmd))) {
+               WARNING("copy from user error getting migrate memory command...\n");
                return -EFAULT;
            }
        
-           printk("moving guest %s vcore %d to CPU %d\n", guest->name, cmd.vcore_id, cmd.pcore_id);
+           INFO("moving guest %s memory at gpa %p to memory with affinity for CPU %d\n", guest->name, (void*)(cmd.gpa), cmd.pcore_id);
 
-           v3_move_vm_core(guest->v3_ctx, cmd.vcore_id, cmd.pcore_id);
+           if (v3_move_vm_mem(guest->v3_ctx, (void*)(cmd.gpa), cmd.pcore_id)) {
+               ERROR("Could not move memory\n");
+               return -EFAULT;
+           }
 
            break;
        }
@@ -232,7 +390,7 @@ static long v3_vm_ioctl(struct file * filp,
            }
            
            
-           printk("\tUnhandled ctrl cmd: %d\n", ioctl);
+           WARNING("\tUnhandled ctrl cmd: %d\n", ioctl);
            return -EINVAL;
        }
     }
@@ -277,17 +435,19 @@ extern u32 frees;
 int create_palacios_vm(struct v3_guest * guest)  {
     int err;
 
-    init_vm_extensions(guest);
+    if (init_vm_extensions(guest) < 0) {
+        WARNING("palacios: failed to initialize extensions\n");
+        return -1;
+    }
 
-    guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
+    guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name, (0x1 << num_online_cpus()) - 1);
 
     if (guest->v3_ctx == NULL) { 
-       printk("palacios: failed to create vm\n");
-       return -1;
+       WARNING("palacios: failed to create vm\n");
+        goto out_err;
     }
 
-
-    printk("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
+    NOTICE("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
 
     cdev_init(&(guest->cdev), &v3_vm_fops);
 
@@ -295,25 +455,30 @@ int create_palacios_vm(struct v3_guest * guest)  {
     guest->cdev.ops = &v3_vm_fops;
 
 
-    printk("Adding VM device\n");
+    INFO("Adding VM device\n");
     err = cdev_add(&(guest->cdev), guest->vm_dev, 1);
 
     if (err) {
-       printk("Fails to add cdev\n");
-       v3_free_vm(guest->v3_ctx);
-       return -1;
+       WARNING("Fails to add cdev\n");
+        goto out_err1;
     }
 
     if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){
-       printk("Fails to create device\n");
-       cdev_del(&(guest->cdev));
-       v3_free_vm(guest->v3_ctx);
-       return -1;
+       WARNING("Fails to create device\n");
+        goto out_err2;
     }
 
-    printk("palacios: vm created at /dev/v3-vm%d\n", MINOR(guest->vm_dev));
+    NOTICE("palacios: vm created at /dev/v3-vm%d\n", MINOR(guest->vm_dev));
 
     return 0;
+
+out_err2:
+    cdev_del(&(guest->cdev));
+out_err1:
+    v3_free_vm(guest->v3_ctx);
+out_err:
+    deinit_vm_extensions(guest);
+    return -1;
 }
 
 
@@ -322,14 +487,20 @@ int create_palacios_vm(struct v3_guest * guest)  {
 
 int free_palacios_vm(struct v3_guest * guest) {
 
-    v3_free_vm(guest->v3_ctx);
+    if (v3_free_vm(guest->v3_ctx)<0) { 
+       return -1;
+    }
 
     device_destroy(v3_class, guest->vm_dev);
 
     cdev_del(&(guest->cdev));
 
-    vfree(guest->img);
-    kfree(guest);
+    free_guest_ctrls(guest);
+
+    deinit_vm_extensions(guest);
+
+    palacios_vfree(guest->img);
+    palacios_free(guest);
 
     return 0;
 }