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.


added error checking to guest launch to handle core mapping bugs
[palacios.git] / linux_module / vm.c
1 /* 
2  * VM specific Controls
3  * (c) Jack Lange, 2010
4  */
5
6 #include <linux/device.h>
7 #include <linux/cdev.h>
8 #include <linux/errno.h>
9 #include <linux/percpu.h>
10 #include <linux/fs.h>
11 #include <linux/uaccess.h>
12 #include <linux/poll.h>
13 #include <linux/anon_inodes.h>
14 #include <linux/sched.h>
15 #include <linux/vmalloc.h>
16 #include <linux/file.h>
17 #include <linux/spinlock.h>
18 #include <linux/rbtree.h>
19
20 #include <palacios/vmm.h>
21
22 #include "palacios.h"
23 #include "vm.h"
24 #include "linux-exts.h"
25
26
27 struct vm_ctrl {
28     unsigned int cmd;
29
30     int (*handler)(struct v3_guest * guest, 
31                    unsigned int cmd, unsigned long arg, 
32                    void * priv_data);
33
34     void * priv_data;
35
36     struct rb_node tree_node;
37 };
38
39
40 static inline struct vm_ctrl * __insert_ctrl(struct v3_guest * vm, 
41                                              struct vm_ctrl * ctrl) {
42     struct rb_node ** p = &(vm->vm_ctrls.rb_node);
43     struct rb_node * parent = NULL;
44     struct vm_ctrl * tmp_ctrl = NULL;
45
46     while (*p) {
47         parent = *p;
48         tmp_ctrl = rb_entry(parent, struct vm_ctrl, tree_node);
49
50         if (ctrl->cmd < tmp_ctrl->cmd) {
51             p = &(*p)->rb_left;
52         } else if (ctrl->cmd > tmp_ctrl->cmd) {
53             p = &(*p)->rb_right;
54         } else {
55             return tmp_ctrl;
56         }
57     }
58
59     rb_link_node(&(ctrl->tree_node), parent, p);
60
61     return NULL;
62 }
63
64
65
66 int add_guest_ctrl(struct v3_guest * guest, unsigned int cmd, 
67                    int (*handler)(struct v3_guest * guest, 
68                                   unsigned int cmd, unsigned long arg, 
69                                   void * priv_data),
70                    void * priv_data) {
71     struct vm_ctrl * ctrl = kmalloc(sizeof(struct vm_ctrl), GFP_KERNEL);
72
73     if (ctrl == NULL) {
74         printk("Error: Could not allocate vm ctrl %d\n", cmd);
75         return -1;
76     }
77
78     ctrl->cmd = cmd;
79     ctrl->handler = handler;
80     ctrl->priv_data = priv_data;
81
82     if (__insert_ctrl(guest, ctrl) != NULL) {
83         printk("Could not insert guest ctrl %d\n", cmd);
84         kfree(ctrl);
85         return -1;
86     }
87     
88     rb_insert_color(&(ctrl->tree_node), &(guest->vm_ctrls));
89
90     return 0;
91 }
92
93
94 static struct vm_ctrl * get_ctrl(struct v3_guest * guest, unsigned int cmd) {
95     struct rb_node * n = guest->vm_ctrls.rb_node;
96     struct vm_ctrl * ctrl = NULL;
97
98     while (n) {
99         ctrl = rb_entry(n, struct vm_ctrl, tree_node);
100
101         if (cmd < ctrl->cmd) {
102             n = n->rb_left;
103         } else if (cmd > ctrl->cmd) {
104             n = n->rb_right;
105         } else {
106             return ctrl;
107         }
108     }
109
110     return NULL;
111 }
112
113
114
115
116
117
118
119 extern struct class * v3_class;
120
121
122 static long v3_vm_ioctl(struct file * filp,
123                         unsigned int ioctl, unsigned long arg) {
124
125     struct v3_guest * guest = filp->private_data;
126
127     printk("V3 IOCTL %d\n", ioctl);
128
129     switch (ioctl) {
130         case V3_VM_LAUNCH: {
131             printk("palacios: launching vm\n");
132
133             if (v3_start_vm(guest->v3_ctx, (0x1 << num_online_cpus()) - 1) < 0) { 
134                 printk("palacios: launch of vm failed\n");
135                 return -1;
136             }
137             
138             break;
139         }
140         case V3_VM_STOP: {
141             printk("Stopping VM (%s) (%p)\n", guest->name, guest);
142
143             if (irqs_disabled()) {
144                 printk("WHAT!!?? IRQs are disabled??\n");
145                 break;
146             }
147
148             v3_stop_vm(guest->v3_ctx);
149             break;
150         }
151         case V3_VM_PAUSE: {
152             printk("Pausing VM (%s)\n", guest->name);
153             v3_pause_vm(guest->v3_ctx);
154             break;
155         }
156         case V3_VM_CONTINUE: {
157             printk("Continuing VM (%s)\n", guest->name);
158             v3_continue_vm(guest->v3_ctx);
159             break;
160         }
161 #ifdef V3_CONFIG_CHECKPOINT
162         case V3_VM_SAVE: {
163             struct v3_chkpt_info chkpt;
164             void __user * argp = (void __user *)arg;
165
166             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
167
168             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
169                 printk("Copy from user error getting checkpoint info\n");
170                 return -EFAULT;
171             }
172             
173             printk("Saving Guest to %s:%s\n", chkpt.store, chkpt.url);
174
175             if (v3_save_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
176                 printk("Error checkpointing VM state\n");
177                 return -EFAULT;
178             }
179             
180             break;
181         }
182         case V3_VM_LOAD: {
183             struct v3_chkpt_info chkpt;
184             void __user * argp = (void __user *)arg;
185
186             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
187
188             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
189                 printk("Copy from user error getting checkpoint info\n");
190                 return -EFAULT;
191             }
192             
193             printk("Loading Guest to %s:%s\n", chkpt.store, chkpt.url);
194
195             if (v3_load_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
196                 printk("Error Loading VM state\n");
197                 return -EFAULT;
198             }
199             
200             break;
201         }
202 #endif
203         case V3_VM_MOVE_CORE: {
204             struct v3_core_move_cmd cmd;
205             void __user * argp = (void __user *)arg;
206
207             memset(&cmd, 0, sizeof(struct v3_core_move_cmd));
208             
209             if (copy_from_user(&cmd, argp, sizeof(struct v3_core_move_cmd))) {
210                 printk("copy from user error getting migrate command...\n");
211                 return -EFAULT;
212             }
213         
214             printk("moving guest %s vcore %d to CPU %d\n", guest->name, cmd.vcore_id, cmd.pcore_id);
215
216             v3_move_vm_core(guest->v3_ctx, cmd.vcore_id, cmd.pcore_id);
217
218             break;
219         }
220         default: {
221             struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
222
223             if (ctrl) {
224                 return ctrl->handler(guest, ioctl, arg, ctrl->priv_data);
225             }
226             
227             
228             printk("\tUnhandled ctrl cmd: %d\n", ioctl);
229             return -EINVAL;
230         }
231     }
232
233     return 0;
234 }
235
236 static int v3_vm_open(struct inode * inode, struct file * filp) {
237     struct v3_guest * guest = container_of(inode->i_cdev, struct v3_guest, cdev);
238     filp->private_data = guest;
239     return 0;
240 }
241
242
243 static ssize_t v3_vm_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
244     
245     return 0;
246 }
247
248
249 static ssize_t v3_vm_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
250
251     return 0;
252 }
253
254
255 static struct file_operations v3_vm_fops = {
256     .owner = THIS_MODULE,
257     .unlocked_ioctl = v3_vm_ioctl,
258     .compat_ioctl = v3_vm_ioctl,
259     .open = v3_vm_open,
260     .read = v3_vm_read, 
261     .write = v3_vm_write,
262 };
263
264
265 extern u32 pg_allocs;
266 extern u32 pg_frees;
267 extern u32 mallocs;
268 extern u32 frees;
269
270 int create_palacios_vm(struct v3_guest * guest)  {
271     int err;
272
273     init_vm_extensions(guest);
274
275     guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
276
277     if (guest->v3_ctx == NULL) { 
278         printk("palacios: failed to create vm\n");
279         return -1;
280     }
281
282
283     printk("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
284
285     cdev_init(&(guest->cdev), &v3_vm_fops);
286
287     guest->cdev.owner = THIS_MODULE;
288     guest->cdev.ops = &v3_vm_fops;
289
290
291     printk("Adding VM device\n");
292     err = cdev_add(&(guest->cdev), guest->vm_dev, 1);
293
294     if (err) {
295         printk("Fails to add cdev\n");
296         v3_free_vm(guest->v3_ctx);
297         return -1;
298     }
299
300     if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){
301         printk("Fails to create device\n");
302         cdev_del(&(guest->cdev));
303         v3_free_vm(guest->v3_ctx);
304         return -1;
305     }
306
307     printk("palacios: vm created at /dev/v3-vm%d\n", MINOR(guest->vm_dev));
308
309     return 0;
310 }
311
312
313
314
315
316 int free_palacios_vm(struct v3_guest * guest) {
317
318     v3_free_vm(guest->v3_ctx);
319
320     device_destroy(v3_class, guest->vm_dev);
321
322     cdev_del(&(guest->cdev));
323
324     vfree(guest->img);
325     kfree(guest);
326
327     return 0;
328 }