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.


Extensive, Pedantic Error Checking in Linux module, especially for memory
[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.h"
25 #include "mm.h"
26 #include "vm.h"
27
28 #include "linux-exts.h"
29
30
31
32 MODULE_LICENSE("GPL");
33
34 // Module parameter
35 int cpu_list[NR_CPUS] = {};
36 int cpu_list_len = 0;
37 module_param_array(cpu_list, int, &cpu_list_len, 0644);
38 MODULE_PARM_DESC(cpu_list, "Comma-delimited list of CPUs that Palacios will run on");
39
40 int mod_allocs = 0;
41 int mod_frees = 0;
42
43
44 static int v3_major_num = 0;
45
46 static struct v3_guest * guest_map[MAX_VMS] = {[0 ... MAX_VMS - 1] = 0};
47 static struct proc_dir_entry *dir = 0;
48
49 struct class * v3_class = NULL;
50 static struct cdev ctrl_dev;
51
52 static int register_vm(struct v3_guest * guest) {
53     int i = 0;
54
55     for (i = 0; i < MAX_VMS; i++) {
56         if (guest_map[i] == NULL) {
57             guest_map[i] = guest;
58             return i;
59         }
60     }
61
62     return -1;
63 }
64
65
66
67 static long v3_dev_ioctl(struct file * filp,
68                          unsigned int ioctl, unsigned long arg) {
69     void __user * argp = (void __user *)arg;
70     DEBUG("V3 IOCTL %d\n", ioctl);
71
72
73     switch (ioctl) {
74         case V3_CREATE_GUEST:{
75             int vm_minor = 0;
76             struct v3_guest_img user_image;
77             struct v3_guest * guest = palacios_alloc(sizeof(struct v3_guest));
78
79             if (IS_ERR(guest)) {
80                 ERROR("Palacios: Error allocating Kernel guest_image\n");
81                 return -EFAULT;
82             }
83
84             memset(guest, 0, sizeof(struct v3_guest));
85
86             INFO("Palacios: Creating V3 Guest...\n");
87
88             vm_minor = register_vm(guest);
89
90             if (vm_minor == -1) {
91                 ERROR("Palacios Error: Too many VMs are currently running\n");
92                 palacios_free(guest);
93                 return -EFAULT;
94             }
95
96             guest->vm_dev = MKDEV(v3_major_num, vm_minor);
97
98             if (copy_from_user(&user_image, argp, sizeof(struct v3_guest_img))) {
99                 ERROR("Palacios Error: copy from user error getting guest image...\n");
100                 palacios_free(guest);
101                 return -EFAULT;
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                 palacios_free(guest);
112                 return -EFAULT;
113             }
114
115             if (copy_from_user(guest->img, user_image.guest_data, guest->img_size)) {
116                 ERROR("Palacios: Error loading guest data\n");
117                 palacios_free(guest);
118                 return -EFAULT;
119             }      
120
121             strncpy(guest->name, user_image.name, 127);
122
123             INIT_LIST_HEAD(&(guest->exts));
124
125             if (create_palacios_vm(guest) == -1) {
126                 ERROR("Palacios: Error creating guest\n");
127                 palacios_free(guest->img);
128                 palacios_free(guest);
129                 return -EFAULT;
130             }
131
132             return vm_minor;
133             break;
134         }
135         case V3_FREE_GUEST: {
136             unsigned long vm_idx = arg;
137             struct v3_guest * guest = guest_map[vm_idx];
138
139             INFO("Freeing VM (%s) (%p)\n", guest->name, guest);
140
141             free_palacios_vm(guest);
142             guest_map[vm_idx] = NULL;
143             break;
144         }
145         case V3_ADD_MEMORY: {
146             struct v3_mem_region mem;
147             
148             memset(&mem, 0, sizeof(struct v3_mem_region));
149             
150             if (copy_from_user(&mem, argp, sizeof(struct v3_mem_region))) {
151                 ERROR("copy from user error getting mem_region...\n");
152                 return -EFAULT;
153             }
154
155             DEBUG("Adding %llu pages to Palacios memory\n", mem.num_pages);
156
157             if (add_palacios_memory(mem.base_addr, mem.num_pages) == -1) {
158                 ERROR("Error adding memory to Palacios\n");
159                 return -EFAULT;
160             }
161
162             break;
163         }
164
165         default: 
166             ERROR("\tUnhandled\n");
167             return -EINVAL;
168     }
169
170     return 0;
171 }
172
173
174
175 static struct file_operations v3_ctrl_fops = {
176     .owner = THIS_MODULE,
177     .unlocked_ioctl = v3_dev_ioctl,
178     .compat_ioctl = v3_dev_ioctl,
179 };
180
181
182
183 struct proc_dir_entry *palacios_get_procdir(void) 
184 {
185     return dir;
186 }
187
188 static int read_guests(char * buf, char ** start, off_t off, int count,
189                        int * eof, void * data)
190 {
191     int len = 0;
192     unsigned int i = 0;
193     
194     for(i = 0; i < MAX_VMS; i++) {
195         if (guest_map[i] != NULL) {
196             if (len<count) { 
197                 len += snprintf(buf+len, count-len,
198                                 "%s\t/dev/v3-vm%d\n", 
199                                 guest_map[i]->name, i);
200             }
201         }
202     }
203     
204     return len;
205 }
206
207 static int show_mem(char * buf, char ** start, off_t off, int count,
208                     int * eof, void * data)
209 {
210     int len = 0;
211     
212     len = snprintf(buf,count, "%p\n", (void *)get_palacios_base_addr());
213     len += snprintf(buf+len,count-len, "%lld\n", get_palacios_num_pages());
214     
215     return len;
216 }
217
218
219 static int __init v3_init(void) {
220     dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
221     int ret = 0;
222
223
224     palacios_init_mm();
225
226     // Initialize Palacios
227     palacios_vmm_init();
228
229
230     // initialize extensions
231     init_lnx_extensions();
232
233
234     v3_class = class_create(THIS_MODULE, "vms");
235     if (IS_ERR(v3_class)) {
236         ERROR("Failed to register V3 VM device class\n");
237         return PTR_ERR(v3_class);
238     }
239
240     INFO("intializing V3 Control device\n");
241
242     ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee");
243
244     if (ret < 0) {
245         ERROR("Error registering device region for V3 devices\n");
246         goto failure2;
247     }
248
249     v3_major_num = MAJOR(dev);
250
251     dev = MKDEV(v3_major_num, MAX_VMS + 1);
252
253     
254     DEBUG("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev));
255     cdev_init(&ctrl_dev, &v3_ctrl_fops);
256     ctrl_dev.owner = THIS_MODULE;
257     ctrl_dev.ops = &v3_ctrl_fops;
258     cdev_add(&ctrl_dev, dev, 1);
259     
260     device_create(v3_class, NULL, dev, NULL, "v3vee");
261
262     if (ret != 0) {
263         ERROR("Error adding v3 control device\n");
264         goto failure1;
265     }
266
267     dir = proc_mkdir("v3vee", NULL);
268     if(dir) {
269         struct proc_dir_entry *entry;
270
271         entry = create_proc_read_entry("v3-guests", 0444, dir, 
272                                        read_guests, NULL);
273         if (entry) {
274             INFO("/proc/v3vee/v3-guests successfully created\n");
275         } else {
276             ERROR("Could not create proc entry\n");
277             goto failure1;
278         }
279         
280         entry = create_proc_read_entry("v3-mem", 0444, dir,
281                                        show_mem, NULL);
282         if (entry) {
283             INFO("/proc/v3vee/v3-mem successfully added\n");
284         } else {
285             ERROR("Could not create proc entry\n");
286             goto failure1;
287         }
288     } else {
289         ERROR("Could not create proc entry\n");
290         goto failure1;
291     }
292         
293     return 0;
294
295  failure1:
296     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
297  failure2:
298     class_destroy(v3_class);
299
300     return ret;
301 }
302
303
304 static void __exit v3_exit(void) {
305     extern u32 pg_allocs;
306     extern u32 pg_frees;
307     extern u32 mallocs;
308     extern u32 frees;
309
310
311     // should probably try to stop any guests
312
313
314
315     dev_t dev = MKDEV(v3_major_num, MAX_VMS + 1);
316
317     INFO("Removing V3 Control device\n");
318
319
320     palacios_vmm_exit();
321
322     DEBUG("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
323     DEBUG("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
324
325     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
326
327     cdev_del(&ctrl_dev);
328
329     device_destroy(v3_class, dev);
330     class_destroy(v3_class);
331
332
333     deinit_lnx_extensions();
334
335     palacios_deinit_mm();
336
337     remove_proc_entry("v3-guests", dir);
338     remove_proc_entry("v3-mem", dir);
339     remove_proc_entry("v3vee", NULL);
340
341     DEBUG("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
342 }
343
344
345
346 module_init(v3_init);
347 module_exit(v3_exit);
348
349
350
351 void * trace_malloc(size_t size, gfp_t flags) {
352     void * addr = NULL;
353
354     mod_allocs++;
355     addr = kmalloc(size, flags);
356
357     return addr;
358 }
359
360
361 void trace_free(const void * objp) {
362     mod_frees++;
363     kfree(objp);
364 }