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