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.


Assorted cleanup
[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     INFO("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
199
200 #ifdef V3_CONFIG_CHECKPOINT
201         case V3_VM_SAVE: {
202             struct v3_chkpt_info chkpt;
203             void __user * argp = (void __user *)arg;
204
205             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
206
207             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
208                 WARNING("Copy from user error getting checkpoint info\n");
209                 return -EFAULT;
210             }
211             
212             NOTICE("Saving Guest to %s:%s\n", chkpt.store, chkpt.url);
213
214             if (v3_save_vm(guest->v3_ctx, chkpt.store, chkpt.url, chkpt.opts) == -1) {
215                 WARNING("Error checkpointing VM state\n");
216                 return -EFAULT;
217             }
218             
219             break;
220         }
221         case V3_VM_LOAD: {
222             struct v3_chkpt_info chkpt;
223             void __user * argp = (void __user *)arg;
224
225             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
226
227             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
228                 WARNING("Copy from user error getting checkpoint info\n");
229                 return -EFAULT;
230             }
231             
232             NOTICE("Loading Guest from %s:%s\n", chkpt.store, chkpt.url);
233
234             if (v3_load_vm(guest->v3_ctx, chkpt.store, chkpt.url, chkpt.opts) == -1) {
235                 WARNING("Error Loading VM state\n");
236                 return -EFAULT;
237             }
238             
239             break;
240         }
241 #endif
242
243 #ifdef V3_CONFIG_LIVE_MIGRATION  
244         case V3_VM_SEND: {
245             struct v3_chkpt_info chkpt_info;
246             void __user * argp = (void __user *)arg;
247             
248             memset(&chkpt_info,0, sizeof(struct v3_chkpt_info));
249             
250             if(copy_from_user(&chkpt_info, argp, sizeof(struct v3_chkpt_info))){
251                 WARNING("Copy from user error getting checkpoint info\n");
252                 return -EFAULT;
253             }
254             
255             
256             NOTICE("Sending (live-migrating) Guest to %s:%s\n",chkpt_info.store, chkpt_info.url); 
257             
258             if (v3_send_vm(guest->v3_ctx, chkpt_info.store, chkpt_info.url, chkpt_info.opts) == -1) {
259                 WARNING("Error sending VM\n");
260                 return -EFAULT;
261             }
262             
263             break;
264         }
265
266         case V3_VM_RECEIVE: {
267             struct v3_chkpt_info chkpt_info;
268             void __user * argp = (void __user *)arg;
269             
270             memset(&chkpt_info,0, sizeof(struct v3_chkpt_info));
271
272             if(copy_from_user(&chkpt_info, argp, sizeof(struct v3_chkpt_info))){
273                 WARNING("Copy from user error getting checkpoint info\n");
274                 return -EFAULT;
275             }
276             
277             
278             NOTICE("Receiving (live-migrating) Guest to %s:%s\n",chkpt_info.store, chkpt_info.url);
279             
280             if (v3_receive_vm(guest->v3_ctx, chkpt_info.store, chkpt_info.url, chkpt_info.opts) == -1) {
281                 WARNING("Error receiving VM\n");
282                 return -EFAULT;
283             }
284             
285             break;
286         }
287 #endif
288
289         case V3_VM_DEBUG: {
290             struct v3_debug_cmd cmd;
291             struct v3_debug_event evt;
292             void __user * argp = (void __user *)arg;        
293
294             memset(&cmd, 0, sizeof(struct v3_debug_cmd));
295             
296             if (copy_from_user(&cmd, argp, sizeof(struct v3_debug_cmd))) {
297                 ERROR("Error: Could not copy debug command from user space\n");
298                 return -EFAULT;
299             }
300
301             evt.core_id = cmd.core;
302             evt.cmd = cmd.cmd;
303
304             INFO("Debugging VM\n");
305
306             if (v3_deliver_debug_event(guest->v3_ctx, &evt) == -1) {
307                 ERROR("Error could not deliver debug cmd\n");
308                 return -EFAULT;
309             }
310
311             break;
312         }
313         case V3_VM_MOVE_CORE: {
314             struct v3_core_move_cmd cmd;
315             void __user * argp = (void __user *)arg;
316
317             memset(&cmd, 0, sizeof(struct v3_core_move_cmd));
318             
319             if (copy_from_user(&cmd, argp, sizeof(struct v3_core_move_cmd))) {
320                 WARNING("copy from user error getting migrate command...\n");
321                 return -EFAULT;
322             }
323         
324             INFO("moving guest %s vcore %d to CPU %d\n", guest->name, cmd.vcore_id, cmd.pcore_id);
325
326             v3_move_vm_core(guest->v3_ctx, cmd.vcore_id, cmd.pcore_id);
327
328             break;
329         }
330         default: {
331             struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
332
333             if (ctrl) {
334                 return ctrl->handler(guest, ioctl, arg, ctrl->priv_data);
335             }
336             
337             
338             WARNING("\tUnhandled ctrl cmd: %d\n", ioctl);
339             return -EINVAL;
340         }
341     }
342
343     return 0;
344 }
345
346 static int v3_vm_open(struct inode * inode, struct file * filp) {
347     struct v3_guest * guest = container_of(inode->i_cdev, struct v3_guest, cdev);
348     filp->private_data = guest;
349     return 0;
350 }
351
352
353 static ssize_t v3_vm_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
354     
355     return 0;
356 }
357
358
359 static ssize_t v3_vm_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
360
361     return 0;
362 }
363
364
365 static struct file_operations v3_vm_fops = {
366     .owner = THIS_MODULE,
367     .unlocked_ioctl = v3_vm_ioctl,
368     .compat_ioctl = v3_vm_ioctl,
369     .open = v3_vm_open,
370     .read = v3_vm_read, 
371     .write = v3_vm_write,
372 };
373
374
375 extern u32 pg_allocs;
376 extern u32 pg_frees;
377 extern u32 mallocs;
378 extern u32 frees;
379
380 int create_palacios_vm(struct v3_guest * guest)  {
381     int err;
382
383     if (init_vm_extensions(guest) < 0) {
384         WARNING("palacios: failed to initialize extensions\n");
385         return -1;
386     }
387
388     guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
389
390     if (guest->v3_ctx == NULL) { 
391         WARNING("palacios: failed to create vm\n");
392         goto out_err;
393     }
394
395     NOTICE("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
396
397     cdev_init(&(guest->cdev), &v3_vm_fops);
398
399     guest->cdev.owner = THIS_MODULE;
400     guest->cdev.ops = &v3_vm_fops;
401
402
403     INFO("Adding VM device\n");
404     err = cdev_add(&(guest->cdev), guest->vm_dev, 1);
405
406     if (err) {
407         WARNING("Fails to add cdev\n");
408         goto out_err1;
409     }
410
411     if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){
412         WARNING("Fails to create device\n");
413         goto out_err2;
414     }
415
416     NOTICE("palacios: vm created at /dev/v3-vm%d\n", MINOR(guest->vm_dev));
417
418     return 0;
419
420 out_err2:
421     cdev_del(&(guest->cdev));
422 out_err1:
423     v3_free_vm(guest->v3_ctx);
424 out_err:
425     deinit_vm_extensions(guest);
426     return -1;
427 }
428
429
430
431
432
433 int free_palacios_vm(struct v3_guest * guest) {
434
435     if (v3_free_vm(guest->v3_ctx)<0) { 
436         return -1;
437     }
438
439     device_destroy(v3_class, guest->vm_dev);
440
441     cdev_del(&(guest->cdev));
442
443     free_guest_ctrls(guest);
444
445     deinit_vm_extensions(guest);
446
447     palacios_vfree(guest->img);
448     palacios_free(guest);
449
450     return 0;
451 }