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.


Updates to linux module to use linux print macros
[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
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 = kmalloc(sizeof(struct vm_ctrl), GFP_KERNEL);
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         kfree(ctrl);
86         return -1;
87     }
88     
89     rb_insert_color(&(ctrl->tree_node), &(guest->vm_ctrls));
90
91     return 0;
92 }
93
94
95 static struct vm_ctrl * get_ctrl(struct v3_guest * guest, unsigned int cmd) {
96     struct rb_node * n = guest->vm_ctrls.rb_node;
97     struct vm_ctrl * ctrl = NULL;
98
99     while (n) {
100         ctrl = rb_entry(n, struct vm_ctrl, tree_node);
101
102         if (cmd < ctrl->cmd) {
103             n = n->rb_left;
104         } else if (cmd > ctrl->cmd) {
105             n = n->rb_right;
106         } else {
107             return ctrl;
108         }
109     }
110
111     return NULL;
112 }
113
114
115
116
117
118
119
120 extern struct class * v3_class;
121
122
123 static long v3_vm_ioctl(struct file * filp,
124                         unsigned int ioctl, unsigned long arg) {
125
126     struct v3_guest * guest = filp->private_data;
127
128     INFO("V3 IOCTL %d\n", ioctl);
129
130     switch (ioctl) {
131         case V3_VM_LAUNCH: {
132             NOTICE("palacios: launching vm\n");
133
134             if (v3_start_vm(guest->v3_ctx, (0x1 << num_online_cpus()) - 1) < 0) { 
135                 WARNING("palacios: launch of vm failed\n");
136                 return -1;
137             }
138             
139             break;
140         }
141         case V3_VM_STOP: {
142             NOTICE("Stopping VM (%s) (%p)\n", guest->name, guest);
143
144             if (irqs_disabled()) {
145                 ERROR("WHAT!!?? IRQs are disabled??\n");
146                 break;
147             }
148
149             v3_stop_vm(guest->v3_ctx);
150             break;
151         }
152         case V3_VM_PAUSE: {
153             NOTICE("Pausing VM (%s)\n", guest->name);
154             v3_pause_vm(guest->v3_ctx);
155             break;
156         }
157         case V3_VM_CONTINUE: {
158             NOTICE("Continuing VM (%s)\n", guest->name);
159             v3_continue_vm(guest->v3_ctx);
160             break;
161         }
162         case V3_VM_SIMULATE: {
163             NOTICE("Simulating VM (%s) for %lu msecs\n", guest->name, arg);
164             v3_simulate_vm(guest->v3_ctx, arg);
165             break;
166         }
167
168
169 #ifdef V3_CONFIG_CHECKPOINT
170         case V3_VM_SAVE: {
171             struct v3_chkpt_info chkpt;
172             void __user * argp = (void __user *)arg;
173
174             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
175
176             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
177                 WARNING("Copy from user error getting checkpoint info\n");
178                 return -EFAULT;
179             }
180             
181             NOTICE("Saving Guest to %s:%s\n", chkpt.store, chkpt.url);
182
183             if (v3_save_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
184                 WARNING("Error checkpointing VM state\n");
185                 return -EFAULT;
186             }
187             
188             break;
189         }
190         case V3_VM_LOAD: {
191             struct v3_chkpt_info chkpt;
192             void __user * argp = (void __user *)arg;
193
194             memset(&chkpt, 0, sizeof(struct v3_chkpt_info));
195
196             if (copy_from_user(&chkpt, argp, sizeof(struct v3_chkpt_info))) {
197                 WARNING("Copy from user error getting checkpoint info\n");
198                 return -EFAULT;
199             }
200             
201             NOTICE("Loading Guest to %s:%s\n", chkpt.store, chkpt.url);
202
203             if (v3_load_vm(guest->v3_ctx, chkpt.store, chkpt.url) == -1) {
204                 WARNING("Error Loading VM state\n");
205                 return -EFAULT;
206             }
207             
208             break;
209         }
210 #endif
211         case V3_VM_MOVE_CORE: {
212             struct v3_core_move_cmd cmd;
213             void __user * argp = (void __user *)arg;
214
215             memset(&cmd, 0, sizeof(struct v3_core_move_cmd));
216             
217             if (copy_from_user(&cmd, argp, sizeof(struct v3_core_move_cmd))) {
218                 WARNING("copy from user error getting migrate command...\n");
219                 return -EFAULT;
220             }
221         
222             INFO("moving guest %s vcore %d to CPU %d\n", guest->name, cmd.vcore_id, cmd.pcore_id);
223
224             v3_move_vm_core(guest->v3_ctx, cmd.vcore_id, cmd.pcore_id);
225
226             break;
227         }
228         default: {
229             struct vm_ctrl * ctrl = get_ctrl(guest, ioctl);
230
231             if (ctrl) {
232                 return ctrl->handler(guest, ioctl, arg, ctrl->priv_data);
233             }
234             
235             
236             WARNING("\tUnhandled ctrl cmd: %d\n", ioctl);
237             return -EINVAL;
238         }
239     }
240
241     return 0;
242 }
243
244 static int v3_vm_open(struct inode * inode, struct file * filp) {
245     struct v3_guest * guest = container_of(inode->i_cdev, struct v3_guest, cdev);
246     filp->private_data = guest;
247     return 0;
248 }
249
250
251 static ssize_t v3_vm_read(struct file * filp, char __user * buf, size_t size, loff_t * offset) {
252     
253     return 0;
254 }
255
256
257 static ssize_t v3_vm_write(struct file * filp, const char __user * buf, size_t size, loff_t * offset) {
258
259     return 0;
260 }
261
262
263 static struct file_operations v3_vm_fops = {
264     .owner = THIS_MODULE,
265     .unlocked_ioctl = v3_vm_ioctl,
266     .compat_ioctl = v3_vm_ioctl,
267     .open = v3_vm_open,
268     .read = v3_vm_read, 
269     .write = v3_vm_write,
270 };
271
272
273 extern u32 pg_allocs;
274 extern u32 pg_frees;
275 extern u32 mallocs;
276 extern u32 frees;
277
278 int create_palacios_vm(struct v3_guest * guest)  {
279     int err;
280
281     init_vm_extensions(guest);
282
283     guest->v3_ctx = v3_create_vm(guest->img, (void *)guest, guest->name);
284
285     if (guest->v3_ctx == NULL) { 
286         WARNING("palacios: failed to create vm\n");
287         return -1;
288     }
289
290
291     NOTICE("Creating VM device: Major %d, Minor %d\n", MAJOR(guest->vm_dev), MINOR(guest->vm_dev));
292
293     cdev_init(&(guest->cdev), &v3_vm_fops);
294
295     guest->cdev.owner = THIS_MODULE;
296     guest->cdev.ops = &v3_vm_fops;
297
298
299     INFO("Adding VM device\n");
300     err = cdev_add(&(guest->cdev), guest->vm_dev, 1);
301
302     if (err) {
303         WARNING("Fails to add cdev\n");
304         v3_free_vm(guest->v3_ctx);
305         return -1;
306     }
307
308     if (device_create(v3_class, NULL, guest->vm_dev, guest, "v3-vm%d", MINOR(guest->vm_dev)) == NULL){
309         WARNING("Fails to create device\n");
310         cdev_del(&(guest->cdev));
311         v3_free_vm(guest->v3_ctx);
312         return -1;
313     }
314
315     NOTICE("palacios: vm created at /dev/v3-vm%d\n", MINOR(guest->vm_dev));
316
317     return 0;
318 }
319
320
321
322
323
324 int free_palacios_vm(struct v3_guest * guest) {
325
326     v3_free_vm(guest->v3_ctx);
327
328     device_destroy(v3_class, guest->vm_dev);
329
330     cdev_del(&(guest->cdev));
331
332     vfree(guest->img);
333     kfree(guest);
334
335     return 0;
336 }