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.


check for out-of-bounds index when freeing a VM
[palacios.git] / linux_module / main.c
1 /* 
2    Palacios main control interface
3    (c) Jack Lange, 2010
4  */
5
6
7 #include <linux/module.h>
8 #include <linux/moduleparam.h>
9 #include <linux/errno.h>
10 #include <linux/percpu.h>
11 #include <linux/fs.h>
12 #include <linux/uaccess.h>
13 #include <linux/device.h>
14 #include <linux/cdev.h>
15
16 #include <linux/io.h>
17
18 #include <linux/file.h>
19 #include <linux/spinlock.h>
20 #include <linux/kthread.h>
21
22 #include <linux/proc_fs.h>
23
24 #include <palacios/vmm.h>
25
26 #include "palacios.h"
27 #include "mm.h"
28 #include "vm.h"
29
30 #include "linux-exts.h"
31
32
33
34 MODULE_LICENSE("GPL");
35
36 // Module parameter
37 int cpu_list[NR_CPUS] = {};
38 int cpu_list_len = 0;
39 module_param_array(cpu_list, int, &cpu_list_len, 0644);
40 MODULE_PARM_DESC(cpu_list, "Comma-delimited list of CPUs that Palacios will run on");
41
42 int mod_allocs = 0;
43 int mod_frees = 0;
44
45
46 static int v3_major_num = 0;
47
48 static struct v3_guest * guest_map[MAX_VMS] = {[0 ... MAX_VMS - 1] = 0};
49 static struct proc_dir_entry *dir = 0;
50
51 struct class * v3_class = NULL;
52 static struct cdev ctrl_dev;
53
54 static int register_vm(struct v3_guest * guest) {
55     int i = 0;
56
57     for (i = 0; i < MAX_VMS; i++) {
58         if (guest_map[i] == NULL) {
59             guest_map[i] = guest;
60             return i;
61         }
62     }
63
64     return -1;
65 }
66
67
68
69 static long v3_dev_ioctl(struct file * filp,
70                          unsigned int ioctl, unsigned long arg) {
71     void __user * argp = (void __user *)arg;
72     DEBUG("V3 IOCTL %d\n", ioctl);
73
74
75     switch (ioctl) {
76         case V3_CREATE_GUEST:{
77             int vm_minor = 0;
78             struct v3_guest_img user_image;
79             struct v3_guest * guest = palacios_alloc(sizeof(struct v3_guest));
80
81             if (IS_ERR(guest)) {
82                 ERROR("Palacios: Error allocating Kernel guest_image\n");
83                 return -EFAULT;
84             }
85
86             memset(guest, 0, sizeof(struct v3_guest));
87
88             INFO("Palacios: Creating V3 Guest...\n");
89
90             vm_minor = register_vm(guest);
91
92             if (vm_minor == -1) {
93                 ERROR("Palacios Error: Too many VMs are currently running\n");
94                 goto out_err;
95             }
96
97             guest->vm_dev = MKDEV(v3_major_num, vm_minor);
98
99             if (copy_from_user(&user_image, argp, sizeof(struct v3_guest_img))) {
100                 ERROR("Palacios Error: copy from user error getting guest image...\n");
101                 goto out_err1;
102             }
103
104             guest->img_size = user_image.size;
105
106             DEBUG("Palacios: Allocating kernel memory for guest image (%llu bytes)\n", user_image.size);
107             guest->img = vmalloc(guest->img_size);
108
109             if (IS_ERR(guest->img)) {
110                 ERROR("Palacios Error: Could not allocate space for guest image\n");
111                 goto out_err1;
112             }
113
114             if (copy_from_user(guest->img, user_image.guest_data, guest->img_size)) {
115                 ERROR("Palacios: Error loading guest data\n");
116                 goto out_err2;
117             }      
118
119             strncpy(guest->name, user_image.name, 127);
120
121             INIT_LIST_HEAD(&(guest->exts));
122
123             if (create_palacios_vm(guest) == -1) {
124                 ERROR("Palacios: Error creating guest\n");
125                 goto out_err2;
126             }
127
128             return vm_minor;
129
130
131 out_err2:
132             vfree(guest->img);
133 out_err1:
134             guest_map[vm_minor] = NULL; 
135 out_err:
136             palacios_free(guest);
137
138             return -1;
139
140             break;
141         }
142         case V3_FREE_GUEST: {
143             unsigned long vm_idx = arg;
144             struct v3_guest * guest;
145
146             if (vm_idx > MAX_VMS) {
147                 ERROR("Invalid VM index: %ld\n", vm_idx);
148                 return -1;
149             }
150
151             guest = guest_map[vm_idx];
152
153             if (!guest) {
154                 ERROR("No VM at index %ld\n",vm_idx);
155                 return -1;
156             }
157
158             INFO("Freeing VM (%s) (%p)\n", guest->name, guest);
159
160             if (free_palacios_vm(guest)<0) { 
161                 ERROR("Cannot free guest at index %ld\n",vm_idx);
162                 return -1;
163             }
164
165             guest_map[vm_idx] = NULL;
166             break;
167         }
168         case V3_ADD_MEMORY: {
169             struct v3_mem_region mem;
170             
171             memset(&mem, 0, sizeof(struct v3_mem_region));
172             
173             if (copy_from_user(&mem, argp, sizeof(struct v3_mem_region))) {
174                 ERROR("copy from user error getting mem_region...\n");
175                 return -EFAULT;
176             }
177
178             DEBUG("Adding %llu pages to Palacios memory\n", mem.num_pages);
179
180             if (add_palacios_memory(mem.base_addr, mem.num_pages) == -1) {
181                 ERROR("Error adding memory to Palacios\n");
182                 return -EFAULT;
183             }
184
185             break;
186         }
187
188         case V3_RESET_MEMORY: {
189             if (palacios_init_mm() == -1) {
190                 ERROR("Error resetting Palacios memory\n");
191                 return -EFAULT;
192             }
193             break;  
194         }
195
196         default: {
197             struct global_ctrl * ctrl = get_global_ctrl(ioctl);
198             
199             if (ctrl) {
200                 return ctrl->handler(ioctl, arg);
201             }
202
203             WARNING("\tUnhandled global ctrl cmd: %d\n", ioctl);
204
205             return -EINVAL;
206         }
207     }
208
209     return 0;
210 }
211
212
213
214 static struct file_operations v3_ctrl_fops = {
215     .owner = THIS_MODULE,
216     .unlocked_ioctl = v3_dev_ioctl,
217     .compat_ioctl = v3_dev_ioctl,
218 };
219
220
221
222 struct proc_dir_entry *palacios_get_procdir(void) 
223 {
224     return dir;
225 }
226
227 static int read_guests(char * buf, char ** start, off_t off, int count,
228                        int * eof, void * data)
229 {
230     int len = 0;
231     unsigned int i = 0;
232     
233     for(i = 0; i < MAX_VMS; i++) {
234         if (guest_map[i] != NULL) {
235             if (len<count) { 
236                 len += snprintf(buf+len, count-len,
237                                 "%s\t/dev/v3-vm%d\n", 
238                                 guest_map[i]->name, i);
239             }
240         }
241     }
242     
243     return len;
244 }
245
246 static int show_mem(char * buf, char ** start, off_t off, int count,
247                     int * eof, void * data)
248 {
249     int len = 0;
250     
251     len = snprintf(buf,count, "%p\n", (void *)get_palacios_base_addr());
252     len += snprintf(buf+len,count-len, "%lld\n", get_palacios_num_pages());
253     
254     return len;
255 }
256
257
258 static int __init v3_init(void) {
259     dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
260     int ret = 0;
261
262
263     palacios_init_mm();
264
265     // Initialize Palacios
266     palacios_vmm_init();
267
268
269     // initialize extensions
270     init_lnx_extensions();
271
272
273     v3_class = class_create(THIS_MODULE, "vms");
274     if (IS_ERR(v3_class)) {
275         ERROR("Failed to register V3 VM device class\n");
276         return PTR_ERR(v3_class);
277     }
278
279     INFO("intializing V3 Control device\n");
280
281     ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee");
282
283     if (ret < 0) {
284         ERROR("Error registering device region for V3 devices\n");
285         goto failure2;
286     }
287
288     v3_major_num = MAJOR(dev);
289
290     dev = MKDEV(v3_major_num, MAX_VMS + 1);
291
292     
293     DEBUG("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev));
294     cdev_init(&ctrl_dev, &v3_ctrl_fops);
295     ctrl_dev.owner = THIS_MODULE;
296     ctrl_dev.ops = &v3_ctrl_fops;
297     cdev_add(&ctrl_dev, dev, 1);
298     
299     device_create(v3_class, NULL, dev, NULL, "v3vee");
300
301     if (ret != 0) {
302         ERROR("Error adding v3 control device\n");
303         goto failure1;
304     }
305
306     dir = proc_mkdir("v3vee", NULL);
307     if(dir) {
308         struct proc_dir_entry *entry;
309
310         entry = create_proc_read_entry("v3-guests", 0444, dir, 
311                                        read_guests, NULL);
312         if (entry) {
313             INFO("/proc/v3vee/v3-guests successfully created\n");
314         } else {
315             ERROR("Could not create proc entry\n");
316             goto failure1;
317         }
318         
319         entry = create_proc_read_entry("v3-mem", 0444, dir,
320                                        show_mem, NULL);
321         if (entry) {
322             INFO("/proc/v3vee/v3-mem successfully added\n");
323         } else {
324             ERROR("Could not create proc entry\n");
325             goto failure1;
326         }
327     } else {
328         ERROR("Could not create proc entry\n");
329         goto failure1;
330     }
331         
332     return 0;
333
334  failure1:
335     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
336  failure2:
337     class_destroy(v3_class);
338
339     return ret;
340 }
341
342
343 static void __exit v3_exit(void) {
344     extern u32 pg_allocs;
345     extern u32 pg_frees;
346     extern u32 mallocs;
347     extern u32 frees;
348     int i = 0;
349     struct v3_guest * guest;
350     dev_t dev;
351
352
353     /* Stop and free any running VMs */ 
354     for (i = 0; i < MAX_VMS; i++) {
355         if (guest_map[i] != NULL) {
356                 guest = (struct v3_guest *)guest_map[i];
357
358                 if (v3_stop_vm(guest->v3_ctx) < 0) 
359                         ERROR("Couldn't stop VM %d\n", i);
360
361                 free_palacios_vm(guest);
362                 guest_map[i] = NULL;
363         }
364     }
365
366     dev = MKDEV(v3_major_num, MAX_VMS + 1);
367
368     INFO("Removing V3 Control device\n");
369
370
371     palacios_vmm_exit();
372
373     DEBUG("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
374     DEBUG("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
375
376     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
377
378     cdev_del(&ctrl_dev);
379
380     device_destroy(v3_class, dev);
381     class_destroy(v3_class);
382
383
384     deinit_lnx_extensions();
385
386     palacios_deinit_mm();
387
388     remove_proc_entry("v3-guests", dir);
389     remove_proc_entry("v3-mem", dir);
390     remove_proc_entry("v3vee", NULL);
391
392     DEBUG("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
393 }
394
395
396
397 module_init(v3_init);
398 module_exit(v3_exit);
399
400
401
402 void * trace_malloc(size_t size, gfp_t flags) {
403     void * addr = NULL;
404
405     mod_allocs++;
406     addr = kmalloc(size, flags);
407
408     return addr;
409 }
410
411
412 void trace_free(const void * objp) {
413     mod_frees++;
414     kfree(objp);
415 }