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.


stop and free all VMs on Linux module exit
[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 = guest_map[vm_idx];
145
146             if (!guest) {
147                 ERROR("No VM at index %ld\n",vm_idx);
148                 return -1;
149             }
150
151             INFO("Freeing VM (%s) (%p)\n", guest->name, guest);
152
153             free_palacios_vm(guest);
154             guest_map[vm_idx] = NULL;
155             break;
156         }
157         case V3_ADD_MEMORY: {
158             struct v3_mem_region mem;
159             
160             memset(&mem, 0, sizeof(struct v3_mem_region));
161             
162             if (copy_from_user(&mem, argp, sizeof(struct v3_mem_region))) {
163                 ERROR("copy from user error getting mem_region...\n");
164                 return -EFAULT;
165             }
166
167             DEBUG("Adding %llu pages to Palacios memory\n", mem.num_pages);
168
169             if (add_palacios_memory(mem.base_addr, mem.num_pages) == -1) {
170                 ERROR("Error adding memory to Palacios\n");
171                 return -EFAULT;
172             }
173
174             break;
175         }
176
177         default: 
178             ERROR("\tUnhandled\n");
179             return -EINVAL;
180     }
181
182     return 0;
183 }
184
185
186
187 static struct file_operations v3_ctrl_fops = {
188     .owner = THIS_MODULE,
189     .unlocked_ioctl = v3_dev_ioctl,
190     .compat_ioctl = v3_dev_ioctl,
191 };
192
193
194
195 struct proc_dir_entry *palacios_get_procdir(void) 
196 {
197     return dir;
198 }
199
200 static int read_guests(char * buf, char ** start, off_t off, int count,
201                        int * eof, void * data)
202 {
203     int len = 0;
204     unsigned int i = 0;
205     
206     for(i = 0; i < MAX_VMS; i++) {
207         if (guest_map[i] != NULL) {
208             if (len<count) { 
209                 len += snprintf(buf+len, count-len,
210                                 "%s\t/dev/v3-vm%d\n", 
211                                 guest_map[i]->name, i);
212             }
213         }
214     }
215     
216     return len;
217 }
218
219 static int show_mem(char * buf, char ** start, off_t off, int count,
220                     int * eof, void * data)
221 {
222     int len = 0;
223     
224     len = snprintf(buf,count, "%p\n", (void *)get_palacios_base_addr());
225     len += snprintf(buf+len,count-len, "%lld\n", get_palacios_num_pages());
226     
227     return len;
228 }
229
230
231 static int __init v3_init(void) {
232     dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
233     int ret = 0;
234
235
236     palacios_init_mm();
237
238     // Initialize Palacios
239     palacios_vmm_init();
240
241
242     // initialize extensions
243     init_lnx_extensions();
244
245
246     v3_class = class_create(THIS_MODULE, "vms");
247     if (IS_ERR(v3_class)) {
248         ERROR("Failed to register V3 VM device class\n");
249         return PTR_ERR(v3_class);
250     }
251
252     INFO("intializing V3 Control device\n");
253
254     ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee");
255
256     if (ret < 0) {
257         ERROR("Error registering device region for V3 devices\n");
258         goto failure2;
259     }
260
261     v3_major_num = MAJOR(dev);
262
263     dev = MKDEV(v3_major_num, MAX_VMS + 1);
264
265     
266     DEBUG("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev));
267     cdev_init(&ctrl_dev, &v3_ctrl_fops);
268     ctrl_dev.owner = THIS_MODULE;
269     ctrl_dev.ops = &v3_ctrl_fops;
270     cdev_add(&ctrl_dev, dev, 1);
271     
272     device_create(v3_class, NULL, dev, NULL, "v3vee");
273
274     if (ret != 0) {
275         ERROR("Error adding v3 control device\n");
276         goto failure1;
277     }
278
279     dir = proc_mkdir("v3vee", NULL);
280     if(dir) {
281         struct proc_dir_entry *entry;
282
283         entry = create_proc_read_entry("v3-guests", 0444, dir, 
284                                        read_guests, NULL);
285         if (entry) {
286             INFO("/proc/v3vee/v3-guests successfully created\n");
287         } else {
288             ERROR("Could not create proc entry\n");
289             goto failure1;
290         }
291         
292         entry = create_proc_read_entry("v3-mem", 0444, dir,
293                                        show_mem, NULL);
294         if (entry) {
295             INFO("/proc/v3vee/v3-mem successfully added\n");
296         } else {
297             ERROR("Could not create proc entry\n");
298             goto failure1;
299         }
300     } else {
301         ERROR("Could not create proc entry\n");
302         goto failure1;
303     }
304         
305     return 0;
306
307  failure1:
308     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
309  failure2:
310     class_destroy(v3_class);
311
312     return ret;
313 }
314
315
316 static void __exit v3_exit(void) {
317     extern u32 pg_allocs;
318     extern u32 pg_frees;
319     extern u32 mallocs;
320     extern u32 frees;
321     int i = 0;
322     struct v3_guest * guest;
323     dev_t dev;
324
325
326     /* Stop and free any running VMs */ 
327     for (i = 0; i < MAX_VMS; i++) {
328         if (guest_map[i] != NULL) {
329                 guest = (struct v3_guest *)guest_map[i];
330
331                 if (v3_stop_vm(guest->v3_ctx) < 0) 
332                         ERROR("Couldn't stop VM %d\n", i);
333
334                 free_palacios_vm(guest);
335                 guest_map[i] = NULL;
336         }
337     }
338
339     dev = MKDEV(v3_major_num, MAX_VMS + 1);
340
341     INFO("Removing V3 Control device\n");
342
343
344     palacios_vmm_exit();
345
346     DEBUG("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
347     DEBUG("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
348
349     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
350
351     cdev_del(&ctrl_dev);
352
353     device_destroy(v3_class, dev);
354     class_destroy(v3_class);
355
356
357     deinit_lnx_extensions();
358
359     palacios_deinit_mm();
360
361     remove_proc_entry("v3-guests", dir);
362     remove_proc_entry("v3-mem", dir);
363     remove_proc_entry("v3vee", NULL);
364
365     DEBUG("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
366 }
367
368
369
370 module_init(v3_init);
371 module_exit(v3_exit);
372
373
374
375 void * trace_malloc(size_t size, gfp_t flags) {
376     void * addr = NULL;
377
378     mod_allocs++;
379     addr = kmalloc(size, flags);
380
381     return addr;
382 }
383
384
385 void trace_free(const void * objp) {
386     mod_frees++;
387     kfree(objp);
388 }