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.


Paranoid error checking in userspace utils
[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         case V3_VM_DEBUG: {
213             struct v3_debug_cmd cmd;
214             struct v3_debug_event evt;
215             void __user * argp = (void __user *)arg;        
216
217             memset(&cmd, 0, sizeof(struct v3_debug_cmd));
218             
219             if (copy_from_user(&cmd, argp, sizeof(struct v3_debug_cmd))) {
220                 ERROR("Error: Could not copy debug command from user space\n");
221                 return -EFAULT;
222             }
223
224             evt.core_id = cmd.core;
225             evt.cmd = cmd.cmd;
226
227             INFO("Debugging VM\n");
228
229             if (v3_deliver_debug_event(guest->v3_ctx, &evt) == -1) {
230                 ERROR("Error could not deliver debug cmd\n");
231                 return -EFAULT;
232             }
233
234             break;
235         }
236         case V3_VM_MOVE_CORE: {
237             struct v3_core_move_cmd cmd;
238             void __user * argp = (void __user *)arg;
239
240             memset(&cmd, 0, sizeof(struct v3_core_move_cmd));
241             
242             if (copy_from_user(&cmd, argp, sizeof(struct v3_core_move_cmd))) {
243                 WARNING("copy from user error getting migrate command...\n");
244                 return -EFAULT;
245             }
246         
247             INFO("moving guest %s vcore %d to CPU %d\n", guest->name, cmd.vcore_id, cmd.pcore_id);
248
249             v3_move_vm_core(guest->v3_ctx, cmd.vcore_id, cmd.pcore_id);
250
251             break;
252         }
253         default: {
254             struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
255
256             if (ctrl) {
257                 return ctrl->handler(guest, ioctl, arg, ctrl->priv_data);
258             }
259             
260             
261             WARNING("\tUnhandled ctrl cmd: %d\n", ioctl);
262             return -EINVAL;
263         }
264     }
265
266     return 0;
267 }
268
269 static int v3_vm_open(struct inode * inode, struct file * filp) {
270     struct v3_guest * guest = container_of(inode->i_cdev, struct v3_guest, cdev);
271     filp->private_data = guest;
272     return 0;
273 }
274
275
276 static ssize_t v3_vm_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
277     
278     return 0;
279 }
280
281
282 static ssize_t v3_vm_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
283
284     return 0;
285 }
286
287
288 static struct file_operations v3_vm_fops = {
289     .owner = THIS_MODULE,
290     .unlocked_ioctl = v3_vm_ioctl,
291     .compat_ioctl = v3_vm_ioctl,
292     .open = v3_vm_open,
293     .read = v3_vm_read, 
294     .write = v3_vm_write,
295 };
296
297
298 extern u32 pg_allocs;
299 extern u32 pg_frees;
300 extern u32 mallocs;
301 extern u32 frees;
302
303 int create_palacios_vm(struct v3_guest * guest)  {
304     int err;
305
306     init_vm_extensions(guest);
307
308     guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
309
310     if (guest->v3_ctx == NULL) { 
311         WARNING("palacios: failed to create vm\n");
312         return -1;
313     }
314
315
316     NOTICE("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
317
318     cdev_init(&(guest->cdev), &v3_vm_fops);
319
320     guest->cdev.owner = THIS_MODULE;
321     guest->cdev.ops = &v3_vm_fops;
322
323
324     INFO("Adding VM device\n");
325     err = cdev_add(&(guest->cdev), guest->vm_dev, 1);
326
327     if (err) {
328         WARNING("Fails to add cdev\n");
329         v3_free_vm(guest->v3_ctx);
330         return -1;
331     }
332
333     if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){
334         WARNING("Fails to create device\n");
335         cdev_del(&(guest->cdev));
336         v3_free_vm(guest->v3_ctx);
337         return -1;
338     }
339
340     NOTICE("palacios: vm created at /dev/v3-vm%d\n", MINOR(guest->vm_dev));
341
342     return 0;
343 }
344
345
346
347
348
349 int free_palacios_vm(struct v3_guest * guest) {
350
351     v3_free_vm(guest->v3_ctx);
352
353     device_destroy(v3_class, guest->vm_dev);
354
355     cdev_del(&(guest->cdev));
356
357     vfree(guest->img);
358     palacios_free(guest);
359
360     return 0;
361 }