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.


Minor PMU bugfix
[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 #include <linux/module.h>
20
21 #include <palacios/vmm.h>
22 #include <palacios/vmm_host_events.h>
23
24 #include "palacios.h"
25 #include "vm.h"
26 #include "linux-exts.h"
27
28
29 struct vm_ctrl {
30     unsigned int cmd;
31
32     int (*handler)(struct v3_guest * guest, 
33                    unsigned int cmd, unsigned long arg, 
34                    void * priv_data);
35
36     void * priv_data;
37
38     struct rb_node tree_node;
39 };
40
41
42 static inline struct vm_ctrl * __insert_ctrl(struct v3_guest * vm, 
43                                              struct vm_ctrl * ctrl) {
44     struct rb_node ** p = &(vm->vm_ctrls.rb_node);
45     struct rb_node * parent = NULL;
46     struct vm_ctrl * tmp_ctrl = NULL;
47
48     while (*p) {
49         parent = *p;
50         tmp_ctrl = rb_entry(parent, struct vm_ctrl, tree_node);
51
52         if (ctrl->cmd < tmp_ctrl->cmd) {
53             p = &(*p)->rb_left;
54         } else if (ctrl->cmd > tmp_ctrl->cmd) {
55             p = &(*p)->rb_right;
56         } else {
57             return tmp_ctrl;
58         }
59     }
60
61     rb_link_node(&(ctrl->tree_node), parent, p);
62
63     return NULL;
64 }
65
66
67
68 int add_guest_ctrl(struct v3_guest * guest, unsigned int cmd, 
69                    int (*handler)(struct v3_guest * guest, 
70                                   unsigned int cmd, unsigned long arg, 
71                                   void * priv_data),
72                    void * priv_data) {
73     struct vm_ctrl * ctrl = palacios_alloc(sizeof(struct vm_ctrl));
74
75     if (ctrl == NULL) {
76         WARNING("Error: Could not allocate vm ctrl %d\n", cmd);
77         return -1;
78     }
79
80     ctrl->cmd = cmd;
81     ctrl->handler = handler;
82     ctrl->priv_data = priv_data;
83
84     if (__insert_ctrl(guest, ctrl) != NULL) {
85         WARNING("Could not insert guest ctrl %d\n", cmd);
86         palacios_free(ctrl);
87         return -1;
88     }
89     
90     rb_insert_color(&(ctrl->tree_node), &(guest->vm_ctrls));
91
92     return 0;
93 }
94
95
96
97
98 static struct vm_ctrl * get_ctrl(struct v3_guest * guest, unsigned int cmd) {
99     struct rb_node * n = guest->vm_ctrls.rb_node;
100     struct vm_ctrl * ctrl = NULL;
101
102     while (n) {
103         ctrl = rb_entry(n, struct vm_ctrl, tree_node);
104
105         if (cmd < ctrl->cmd) {
106             n = n->rb_left;
107         } else if (cmd > ctrl->cmd) {
108             n = n->rb_right;
109         } else {
110             return ctrl;
111         }
112     }
113
114     return NULL;
115 }
116
117 int remove_guest_ctrl(struct v3_guest * guest, unsigned int cmd) {
118     struct vm_ctrl * ctrl = get_ctrl(guest, cmd);
119
120     if (ctrl == NULL) {
121         INFO("Could not find control (%d) to remove\n", cmd);
122         return -1;
123     }
124
125     rb_erase(&(ctrl->tree_node), &(guest->vm_ctrls));
126
127     kfree(ctrl);
128
129     return 0;
130 }
131
132 static void free_guest_ctrls(struct v3_guest * guest) {
133     struct rb_node * node = rb_first(&(guest->vm_ctrls));
134     struct vm_ctrl * ctrl = NULL;
135
136     while (node) {
137         ctrl = rb_entry(node, struct vm_ctrl, tree_node);
138
139         node = rb_next(node);
140         
141         WARNING("Cleaning up guest ctrl that was not removed explicitly (%d)\n", ctrl->cmd);
142
143         kfree(ctrl);
144     }
145 }
146
147
148
149
150
151
152 extern struct class * v3_class;
153
154
155 static long v3_vm_ioctl(struct file * filp,
156                         unsigned int ioctl, unsigned long arg) {
157
158     struct v3_guest * guest = filp->private_data;
159
160     INFO("V3 IOCTL %d\n", ioctl);
161
162     switch (ioctl) {
163         case V3_VM_LAUNCH: {
164             NOTICE("palacios: launching vm\n");
165
166             if (v3_start_vm(guest->v3_ctx, (0x1 << num_online_cpus()) - 1) < 0) { 
167                 WARNING("palacios: launch of vm failed\n");
168                 return -1;
169             }
170             
171             break;
172         }
173         case V3_VM_STOP: {
174             NOTICE("Stopping VM (%s) (%p)\n", guest->name, guest);
175
176             if (irqs_disabled()) {
177                 ERROR("WHAT!!?? IRQs are disabled??\n");
178                 break;
179             }
180
181             v3_stop_vm(guest->v3_ctx);
182             break;
183         }
184         case V3_VM_PAUSE: {
185             NOTICE("Pausing VM (%s)\n", guest->name);
186             v3_pause_vm(guest->v3_ctx);
187             break;
188         }
189         case V3_VM_CONTINUE: {
190             NOTICE("Continuing VM (%s)\n", guest->name);
191             v3_continue_vm(guest->v3_ctx);
192             break;
193         }
194         case V3_VM_SIMULATE: {
195             NOTICE("Simulating VM (%s) for %lu msecs\n", guest->name, arg);
196             v3_simulate_vm(guest->v3_ctx, arg);
197             break;
198         }
199
200
201 #ifdef V3_CONFIG_CHECKPOINT
202         case V3_VM_SAVE: {
203             struct v3_chkpt_info chkpt;
204             void __user * argp = (void __user *)arg;
205
206             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
207
208             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
209                 WARNING("Copy from user error getting checkpoint info\n");
210                 return -EFAULT;
211             }
212             
213             NOTICE("Saving Guest to %s:%s\n", chkpt.store, chkpt.url);
214
215             if (v3_save_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
216                 WARNING("Error checkpointing VM state\n");
217                 return -EFAULT;
218             }
219             
220             break;
221         }
222         case V3_VM_LOAD: {
223             struct v3_chkpt_info chkpt;
224             void __user * argp = (void __user *)arg;
225
226             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
227
228             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
229                 WARNING("Copy from user error getting checkpoint info\n");
230                 return -EFAULT;
231             }
232             
233             NOTICE("Loading Guest from %s:%s\n", chkpt.store, chkpt.url);
234
235             if (v3_load_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
236                 WARNING("Error Loading VM state\n");
237                 return -EFAULT;
238             }
239             
240             break;
241         }
242 #endif
243
244 #ifdef V3_CONFIG_LIVE_MIGRATION  
245         case V3_VM_SEND: {
246             struct v3_chkpt_info chkpt_info;
247             void __user * argp = (void __user *)arg;
248             
249             memset(&chkpt_info,0, sizeof(struct v3_chkpt_info));
250             
251             if(copy_from_user(&chkpt_info, argp, sizeof(struct v3_chkpt_info))){
252                 WARNING("Copy from user error getting checkpoint info\n");
253                 return -EFAULT;
254             }
255             
256             
257             NOTICE("Sending (live-migrating) Guest to %s:%s\n",chkpt_info.store, chkpt_info.url); 
258             
259             if (v3_send_vm(guest->v3_ctx, chkpt_info.store, chkpt_info.url) == -1) {
260                 WARNING("Error sending VM\n");
261                 return -EFAULT;
262             }
263             
264             break;
265         }
266
267         case V3_VM_RECEIVE: {
268             struct v3_chkpt_info chkpt_info;
269             void __user * argp = (void __user *)arg;
270             
271             memset(&chkpt_info,0, sizeof(struct v3_chkpt_info));
272
273             if(copy_from_user(&chkpt_info, argp, sizeof(struct v3_chkpt_info))){
274                 WARNING("Copy from user error getting checkpoint info\n");
275                 return -EFAULT;
276             }
277             
278             
279             NOTICE("Receiving (live-migrating) Guest to %s:%s\n",chkpt_info.store, chkpt_info.url);
280             
281             if (v3_receive_vm(guest->v3_ctx, chkpt_info.store, chkpt_info.url) == -1) {
282                 WARNING("Error receiving VM\n");
283                 return -EFAULT;
284             }
285             
286             break;
287         }
288 #endif
289
290         case V3_VM_DEBUG: {
291             struct v3_debug_cmd cmd;
292             struct v3_debug_event evt;
293             void __user * argp = (void __user *)arg;        
294
295             memset(&cmd, 0, sizeof(struct v3_debug_cmd));
296             
297             if (copy_from_user(&cmd, argp, sizeof(struct v3_debug_cmd))) {
298                 ERROR("Error: Could not copy debug command from user space\n");
299                 return -EFAULT;
300             }
301
302             evt.core_id = cmd.core;
303             evt.cmd = cmd.cmd;
304
305             INFO("Debugging VM\n");
306
307             if (v3_deliver_debug_event(guest->v3_ctx, &evt) == -1) {
308                 ERROR("Error could not deliver debug cmd\n");
309                 return -EFAULT;
310             }
311
312             break;
313         }
314         case V3_VM_MOVE_CORE: {
315             struct v3_core_move_cmd cmd;
316             void __user * argp = (void __user *)arg;
317
318             memset(&cmd, 0, sizeof(struct v3_core_move_cmd));
319             
320             if (copy_from_user(&cmd, argp, sizeof(struct v3_core_move_cmd))) {
321                 WARNING("copy from user error getting migrate command...\n");
322                 return -EFAULT;
323             }
324         
325             INFO("moving guest %s vcore %d to CPU %d\n", guest->name, cmd.vcore_id, cmd.pcore_id);
326
327             v3_move_vm_core(guest->v3_ctx, cmd.vcore_id, cmd.pcore_id);
328
329             break;
330         }
331         default: {
332             struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
333
334             if (ctrl) {
335                 return ctrl->handler(guest, ioctl, arg, ctrl->priv_data);
336             }
337             
338             
339             WARNING("\tUnhandled ctrl cmd: %d\n", ioctl);
340             return -EINVAL;
341         }
342     }
343
344     return 0;
345 }
346
347 static int v3_vm_open(struct inode * inode, struct file * filp) {
348     struct v3_guest * guest = container_of(inode->i_cdev, struct v3_guest, cdev);
349     filp->private_data = guest;
350     return 0;
351 }
352
353
354 static ssize_t v3_vm_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
355     
356     return 0;
357 }
358
359
360 static ssize_t v3_vm_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
361
362     return 0;
363 }
364
365
366 static struct file_operations v3_vm_fops = {
367     .owner = THIS_MODULE,
368     .unlocked_ioctl = v3_vm_ioctl,
369     .compat_ioctl = v3_vm_ioctl,
370     .open = v3_vm_open,
371     .read = v3_vm_read, 
372     .write = v3_vm_write,
373 };
374
375
376 extern u32 pg_allocs;
377 extern u32 pg_frees;
378 extern u32 mallocs;
379 extern u32 frees;
380
381 int create_palacios_vm(struct v3_guest * guest)  {
382     int err;
383
384     if (init_vm_extensions(guest) < 0) {
385         WARNING("palacios: failed to initialize extensions\n");
386         return -1;
387     }
388
389     guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
390
391     if (guest->v3_ctx == NULL) { 
392         WARNING("palacios: failed to create vm\n");
393         goto out_err;
394     }
395
396     NOTICE("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
397
398     cdev_init(&(guest->cdev), &v3_vm_fops);
399
400     guest->cdev.owner = THIS_MODULE;
401     guest->cdev.ops = &v3_vm_fops;
402
403
404     INFO("Adding VM device\n");
405     err = cdev_add(&(guest->cdev), guest->vm_dev, 1);
406
407     if (err) {
408         WARNING("Fails to add cdev\n");
409         goto out_err1;
410     }
411
412     if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){
413         WARNING("Fails to create device\n");
414         goto out_err2;
415     }
416
417     NOTICE("palacios: vm created at /dev/v3-vm%d\n", MINOR(guest->vm_dev));
418
419     return 0;
420
421 out_err2:
422     cdev_del(&(guest->cdev));
423 out_err1:
424     v3_free_vm(guest->v3_ctx);
425 out_err:
426     deinit_vm_extensions(guest);
427     return -1;
428 }
429
430
431
432
433
434 int free_palacios_vm(struct v3_guest * guest) {
435
436     if (v3_free_vm(guest->v3_ctx)<0) { 
437         return -1;
438     }
439
440     device_destroy(v3_class, guest->vm_dev);
441
442     cdev_del(&(guest->cdev));
443
444     free_guest_ctrls(guest);
445
446
447     vfree(guest->img);
448     palacios_free(guest);
449
450     return 0;
451 }