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.


Further cleanup of vnet /proc interface
[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 static struct vm_ctrl * get_ctrl(struct v3_guest * guest, unsigned int cmd) {
97     struct rb_node * n = guest->vm_ctrls.rb_node;
98     struct vm_ctrl * ctrl = NULL;
99
100     while (n) {
101         ctrl = rb_entry(n, struct vm_ctrl, tree_node);
102
103         if (cmd < ctrl->cmd) {
104             n = n->rb_left;
105         } else if (cmd > ctrl->cmd) {
106             n = n->rb_right;
107         } else {
108             return ctrl;
109         }
110     }
111
112     return NULL;
113 }
114
115
116
117
118
119
120
121 extern struct class * v3_class;
122
123
124 static long v3_vm_ioctl(struct file * filp,
125                         unsigned int ioctl, unsigned long arg) {
126
127     struct v3_guest * guest = filp->private_data;
128
129     INFO("V3 IOCTL %d\n", ioctl);
130
131     switch (ioctl) {
132         case V3_VM_LAUNCH: {
133             NOTICE("palacios: launching vm\n");
134
135             if (v3_start_vm(guest->v3_ctx, (0x1 << num_online_cpus()) - 1) < 0) { 
136                 WARNING("palacios: launch of vm failed\n");
137                 return -1;
138             }
139             
140             break;
141         }
142         case V3_VM_STOP: {
143             NOTICE("Stopping VM (%s) (%p)\n", guest->name, guest);
144
145             if (irqs_disabled()) {
146                 ERROR("WHAT!!?? IRQs are disabled??\n");
147                 break;
148             }
149
150             v3_stop_vm(guest->v3_ctx);
151             break;
152         }
153         case V3_VM_PAUSE: {
154             NOTICE("Pausing VM (%s)\n", guest->name);
155             v3_pause_vm(guest->v3_ctx);
156             break;
157         }
158         case V3_VM_CONTINUE: {
159             NOTICE("Continuing VM (%s)\n", guest->name);
160             v3_continue_vm(guest->v3_ctx);
161             break;
162         }
163         case V3_VM_SIMULATE: {
164             NOTICE("Simulating VM (%s) for %lu msecs\n", guest->name, arg);
165             v3_simulate_vm(guest->v3_ctx, arg);
166             break;
167         }
168
169
170 #ifdef V3_CONFIG_CHECKPOINT
171         case V3_VM_SAVE: {
172             struct v3_chkpt_info chkpt;
173             void __user * argp = (void __user *)arg;
174
175             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
176
177             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
178                 WARNING("Copy from user error getting checkpoint info\n");
179                 return -EFAULT;
180             }
181             
182             NOTICE("Saving Guest to %s:%s\n", chkpt.store, chkpt.url);
183
184             if (v3_save_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
185                 WARNING("Error checkpointing VM state\n");
186                 return -EFAULT;
187             }
188             
189             break;
190         }
191         case V3_VM_LOAD: {
192             struct v3_chkpt_info chkpt;
193             void __user * argp = (void __user *)arg;
194
195             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
196
197             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
198                 WARNING("Copy from user error getting checkpoint info\n");
199                 return -EFAULT;
200             }
201             
202             NOTICE("Loading Guest to %s:%s\n", chkpt.store, chkpt.url);
203
204             if (v3_load_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
205                 WARNING("Error Loading VM state\n");
206                 return -EFAULT;
207             }
208             
209             break;
210         }
211 #endif
212
213 #ifdef V3_CONFIG_LIVE_MIGRATION  
214         case V3_VM_SEND: {
215             struct v3_chkpt_info chkpt_info;
216             void __user * argp = (void __user *)arg;
217             
218             memset(&chkpt_info,0, sizeof(struct v3_chkpt_info));
219             
220             if(copy_from_user(&chkpt_info, argp, sizeof(struct v3_chkpt_info))){
221                 WARNING("Copy from user error getting checkpoint info\n");
222                 return -EFAULT;
223             }
224             
225             
226             NOTICE("Sending (live-migrating) Guest to %s:%s\n",chkpt_info.store, chkpt_info.url); 
227             
228             if (v3_send_vm(guest->v3_ctx, chkpt_info.store, chkpt_info.url) == -1) {
229                 WARNING("Error sending VM\n");
230                 return -EFAULT;
231             }
232             
233             break;
234         }
235
236         case V3_VM_RECEIVE: {
237             struct v3_chkpt_info chkpt_info;
238             void __user * argp = (void __user *)arg;
239             
240             memset(&chkpt_info,0, sizeof(struct v3_chkpt_info));
241
242             if(copy_from_user(&chkpt_info, argp, sizeof(struct v3_chkpt_info))){
243                 WARNING("Copy from user error getting checkpoint info\n");
244                 return -EFAULT;
245             }
246             
247             
248             NOTICE("Receiving (live-migrating) Guest to %s:%s\n",chkpt_info.store, chkpt_info.url);
249             
250             if (v3_receive_vm(guest->v3_ctx, chkpt_info.store, chkpt_info.url) == -1) {
251                 WARNING("Error receiving VM\n");
252                 return -EFAULT;
253             }
254             
255             break;
256         }
257 #endif
258
259         case V3_VM_DEBUG: {
260             struct v3_debug_cmd cmd;
261             struct v3_debug_event evt;
262             void __user * argp = (void __user *)arg;        
263
264             memset(&cmd, 0, sizeof(struct v3_debug_cmd));
265             
266             if (copy_from_user(&cmd, argp, sizeof(struct v3_debug_cmd))) {
267                 ERROR("Error: Could not copy debug command from user space\n");
268                 return -EFAULT;
269             }
270
271             evt.core_id = cmd.core;
272             evt.cmd = cmd.cmd;
273
274             INFO("Debugging VM\n");
275
276             if (v3_deliver_debug_event(guest->v3_ctx, &evt) == -1) {
277                 ERROR("Error could not deliver debug cmd\n");
278                 return -EFAULT;
279             }
280
281             break;
282         }
283         case V3_VM_MOVE_CORE: {
284             struct v3_core_move_cmd cmd;
285             void __user * argp = (void __user *)arg;
286
287             memset(&cmd, 0, sizeof(struct v3_core_move_cmd));
288             
289             if (copy_from_user(&cmd, argp, sizeof(struct v3_core_move_cmd))) {
290                 WARNING("copy from user error getting migrate command...\n");
291                 return -EFAULT;
292             }
293         
294             INFO("moving guest %s vcore %d to CPU %d\n", guest->name, cmd.vcore_id, cmd.pcore_id);
295
296             v3_move_vm_core(guest->v3_ctx, cmd.vcore_id, cmd.pcore_id);
297
298             break;
299         }
300         default: {
301             struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
302
303             if (ctrl) {
304                 return ctrl->handler(guest, ioctl, arg, ctrl->priv_data);
305             }
306             
307             
308             WARNING("\tUnhandled ctrl cmd: %d\n", ioctl);
309             return -EINVAL;
310         }
311     }
312
313     return 0;
314 }
315
316 static int v3_vm_open(struct inode * inode, struct file * filp) {
317     struct v3_guest * guest = container_of(inode->i_cdev, struct v3_guest, cdev);
318     filp->private_data = guest;
319     return 0;
320 }
321
322
323 static ssize_t v3_vm_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
324     
325     return 0;
326 }
327
328
329 static ssize_t v3_vm_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
330
331     return 0;
332 }
333
334
335 static struct file_operations v3_vm_fops = {
336     .owner = THIS_MODULE,
337     .unlocked_ioctl = v3_vm_ioctl,
338     .compat_ioctl = v3_vm_ioctl,
339     .open = v3_vm_open,
340     .read = v3_vm_read, 
341     .write = v3_vm_write,
342 };
343
344
345 extern u32 pg_allocs;
346 extern u32 pg_frees;
347 extern u32 mallocs;
348 extern u32 frees;
349
350 int create_palacios_vm(struct v3_guest * guest)  {
351     int err;
352
353     if (init_vm_extensions(guest) < 0) {
354         WARNING("palacios: failed to initialize extensions\n");
355         return -1;
356     }
357
358     guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
359
360     if (guest->v3_ctx == NULL) { 
361         WARNING("palacios: failed to create vm\n");
362         goto out_err;
363     }
364
365     NOTICE("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
366
367     cdev_init(&(guest->cdev), &v3_vm_fops);
368
369     guest->cdev.owner = THIS_MODULE;
370     guest->cdev.ops = &v3_vm_fops;
371
372
373     INFO("Adding VM device\n");
374     err = cdev_add(&(guest->cdev), guest->vm_dev, 1);
375
376     if (err) {
377         WARNING("Fails to add cdev\n");
378         goto out_err1;
379     }
380
381     if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){
382         WARNING("Fails to create device\n");
383         goto out_err2;
384     }
385
386     NOTICE("palacios: vm created at /dev/v3-vm%d\n", MINOR(guest->vm_dev));
387
388     return 0;
389
390 out_err2:
391     cdev_del(&(guest->cdev));
392 out_err1:
393     v3_free_vm(guest->v3_ctx);
394 out_err:
395     deinit_vm_extensions(guest);
396     return -1;
397 }
398
399
400
401
402
403 int free_palacios_vm(struct v3_guest * guest) {
404
405     v3_free_vm(guest->v3_ctx);
406
407     device_destroy(v3_class, guest->vm_dev);
408
409     cdev_del(&(guest->cdev));
410
411     vfree(guest->img);
412     palacios_free(guest);
413
414     return 0;
415 }