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.


d352c36439805e251cca9a936417221994685e31
[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
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 core 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             if (v3_move_vm_core(guest->v3_ctx, cmd.vcore_id, cmd.pcore_id)) { 
327                 ERROR("Could not move core\n");
328                 return -EFAULT;
329             }
330
331             break;
332         }
333         case V3_VM_MOVE_MEM: {
334             struct v3_mem_move_cmd cmd;
335             void __user * argp = (void __user *)arg;
336
337             memset(&cmd, 0, sizeof(struct v3_mem_move_cmd));
338             
339             if (copy_from_user(&cmd, argp, sizeof(struct v3_mem_move_cmd))) {
340                 WARNING("copy from user error getting migrate memory command...\n");
341                 return -EFAULT;
342             }
343         
344             INFO("moving guest %s memory at gpa %p to memory with affinity for CPU %d\n", guest->name, (void*)(cmd.gpa), cmd.pcore_id);
345
346             if (v3_move_vm_mem(guest->v3_ctx, (void*)(cmd.gpa), cmd.pcore_id)) {
347                 ERROR("Could not move memory\n");
348                 return -EFAULT;
349             }
350
351             break;
352         }
353         default: {
354             struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
355
356             if (ctrl) {
357                 return ctrl->handler(guest, ioctl, arg, ctrl->priv_data);
358             }
359             
360             
361             WARNING("\tUnhandled ctrl cmd: %d\n", ioctl);
362             return -EINVAL;
363         }
364     }
365
366     return 0;
367 }
368
369 static int v3_vm_open(struct inode * inode, struct file * filp) {
370     struct v3_guest * guest = container_of(inode->i_cdev, struct v3_guest, cdev);
371     filp->private_data = guest;
372     return 0;
373 }
374
375
376 static ssize_t v3_vm_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
377     
378     return 0;
379 }
380
381
382 static ssize_t v3_vm_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
383
384     return 0;
385 }
386
387
388 static struct file_operations v3_vm_fops = {
389     .owner = THIS_MODULE,
390     .unlocked_ioctl = v3_vm_ioctl,
391     .compat_ioctl = v3_vm_ioctl,
392     .open = v3_vm_open,
393     .read = v3_vm_read, 
394     .write = v3_vm_write,
395 };
396
397
398 extern u32 pg_allocs;
399 extern u32 pg_frees;
400 extern u32 mallocs;
401 extern u32 frees;
402
403 int create_palacios_vm(struct v3_guest * guest)  {
404     int err;
405
406     if (init_vm_extensions(guest) < 0) {
407         WARNING("palacios: failed to initialize extensions\n");
408         return -1;
409     }
410
411     guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name, (0x1 << num_online_cpus()) - 1);
412
413     if (guest->v3_ctx == NULL) { 
414         WARNING("palacios: failed to create vm\n");
415         goto out_err;
416     }
417
418     NOTICE("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
419
420     cdev_init(&(guest->cdev), &v3_vm_fops);
421
422     guest->cdev.owner = THIS_MODULE;
423     guest->cdev.ops = &v3_vm_fops;
424
425
426     INFO("Adding VM device\n");
427     err = cdev_add(&(guest->cdev), guest->vm_dev, 1);
428
429     if (err) {
430         WARNING("Fails to add cdev\n");
431         goto out_err1;
432     }
433
434     if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){
435         WARNING("Fails to create device\n");
436         goto out_err2;
437     }
438
439     NOTICE("palacios: vm created at /dev/v3-vm%d\n", MINOR(guest->vm_dev));
440
441     return 0;
442
443 out_err2:
444     cdev_del(&(guest->cdev));
445 out_err1:
446     v3_free_vm(guest->v3_ctx);
447 out_err:
448     deinit_vm_extensions(guest);
449     return -1;
450 }
451
452
453
454
455
456 int free_palacios_vm(struct v3_guest * guest) {
457
458     if (v3_free_vm(guest->v3_ctx)<0) { 
459         return -1;
460     }
461
462     device_destroy(v3_class, guest->vm_dev);
463
464     cdev_del(&(guest->cdev));
465
466     free_guest_ctrls(guest);
467
468     deinit_vm_extensions(guest);
469
470     palacios_vfree(guest->img);
471     palacios_free(guest);
472
473     return 0;
474 }