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.


Fail gracefully on VM create or free errors
[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                 goto out_err;
93             }
94
95             guest->vm_dev = MKDEV(v3_major_num, vm_minor);
96
97             if (copy_from_user(&user_image, argp, sizeof(struct v3_guest_img))) {
98                 ERROR("Palacios Error: copy from user error getting guest image...\n");
99                 goto out_err1;
100             }
101
102             guest->img_size = user_image.size;
103
104             DEBUG("Palacios: Allocating kernel memory for guest image (%llu bytes)\n", user_image.size);
105             guest->img = vmalloc(guest->img_size);
106
107             if (IS_ERR(guest->img)) {
108                 ERROR("Palacios Error: Could not allocate space for guest image\n");
109                 goto out_err1;
110             }
111
112             if (copy_from_user(guest->img, user_image.guest_data, guest->img_size)) {
113                 ERROR("Palacios: Error loading guest data\n");
114                 goto out_err2;
115             }      
116
117             strncpy(guest->name, user_image.name, 127);
118
119             INIT_LIST_HEAD(&(guest->exts));
120
121             if (create_palacios_vm(guest) == -1) {
122                 ERROR("Palacios: Error creating guest\n");
123                 goto out_err2;
124             }
125
126             return vm_minor;
127
128
129 out_err2:
130             vfree(guest->img);
131 out_err1:
132             guest_map[vm_minor] = NULL; 
133 out_err:
134             palacios_free(guest);
135
136             return -1;
137
138             break;
139         }
140         case V3_FREE_GUEST: {
141             unsigned long vm_idx = arg;
142             struct v3_guest * guest = guest_map[vm_idx];
143
144             if (!guest) {
145                 ERROR("No VM at index %ld\n",vm_idx);
146                 return -1;
147             }
148
149             INFO("Freeing VM (%s) (%p)\n", guest->name, guest);
150
151             free_palacios_vm(guest);
152             guest_map[vm_idx] = NULL;
153             break;
154         }
155         case V3_ADD_MEMORY: {
156             struct v3_mem_region mem;
157             
158             memset(&mem, 0, sizeof(struct v3_mem_region));
159             
160             if (copy_from_user(&mem, argp, sizeof(struct v3_mem_region))) {
161                 ERROR("copy from user error getting mem_region...\n");
162                 return -EFAULT;
163             }
164
165             DEBUG("Adding %llu pages to Palacios memory\n", mem.num_pages);
166
167             if (add_palacios_memory(mem.base_addr, mem.num_pages) == -1) {
168                 ERROR("Error adding memory to Palacios\n");
169                 return -EFAULT;
170             }
171
172             break;
173         }
174
175         default: 
176             ERROR("\tUnhandled\n");
177             return -EINVAL;
178     }
179
180     return 0;
181 }
182
183
184
185 static struct file_operations v3_ctrl_fops = {
186     .owner = THIS_MODULE,
187     .unlocked_ioctl = v3_dev_ioctl,
188     .compat_ioctl = v3_dev_ioctl,
189 };
190
191
192
193 struct proc_dir_entry *palacios_get_procdir(void) 
194 {
195     return dir;
196 }
197
198 static int read_guests(char * buf, char ** start, off_t off, int count,
199                        int * eof, void * data)
200 {
201     int len = 0;
202     unsigned int i = 0;
203     
204     for(i = 0; i < MAX_VMS; i++) {
205         if (guest_map[i] != NULL) {
206             if (len<count) { 
207                 len += snprintf(buf+len, count-len,
208                                 "%s\t/dev/v3-vm%d\n", 
209                                 guest_map[i]->name, i);
210             }
211         }
212     }
213     
214     return len;
215 }
216
217 static int show_mem(char * buf, char ** start, off_t off, int count,
218                     int * eof, void * data)
219 {
220     int len = 0;
221     
222     len = snprintf(buf,count, "%p\n", (void *)get_palacios_base_addr());
223     len += snprintf(buf+len,count-len, "%lld\n", get_palacios_num_pages());
224     
225     return len;
226 }
227
228
229 static int __init v3_init(void) {
230     dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
231     int ret = 0;
232
233
234     palacios_init_mm();
235
236     // Initialize Palacios
237     palacios_vmm_init();
238
239
240     // initialize extensions
241     init_lnx_extensions();
242
243
244     v3_class = class_create(THIS_MODULE, "vms");
245     if (IS_ERR(v3_class)) {
246         ERROR("Failed to register V3 VM device class\n");
247         return PTR_ERR(v3_class);
248     }
249
250     INFO("intializing V3 Control device\n");
251
252     ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee");
253
254     if (ret < 0) {
255         ERROR("Error registering device region for V3 devices\n");
256         goto failure2;
257     }
258
259     v3_major_num = MAJOR(dev);
260
261     dev = MKDEV(v3_major_num, MAX_VMS + 1);
262
263     
264     DEBUG("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev));
265     cdev_init(&ctrl_dev, &v3_ctrl_fops);
266     ctrl_dev.owner = THIS_MODULE;
267     ctrl_dev.ops = &v3_ctrl_fops;
268     cdev_add(&ctrl_dev, dev, 1);
269     
270     device_create(v3_class, NULL, dev, NULL, "v3vee");
271
272     if (ret != 0) {
273         ERROR("Error adding v3 control device\n");
274         goto failure1;
275     }
276
277     dir = proc_mkdir("v3vee", NULL);
278     if(dir) {
279         struct proc_dir_entry *entry;
280
281         entry = create_proc_read_entry("v3-guests", 0444, dir, 
282                                        read_guests, NULL);
283         if (entry) {
284             INFO("/proc/v3vee/v3-guests successfully created\n");
285         } else {
286             ERROR("Could not create proc entry\n");
287             goto failure1;
288         }
289         
290         entry = create_proc_read_entry("v3-mem", 0444, dir,
291                                        show_mem, NULL);
292         if (entry) {
293             INFO("/proc/v3vee/v3-mem successfully added\n");
294         } else {
295             ERROR("Could not create proc entry\n");
296             goto failure1;
297         }
298     } else {
299         ERROR("Could not create proc entry\n");
300         goto failure1;
301     }
302         
303     return 0;
304
305  failure1:
306     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
307  failure2:
308     class_destroy(v3_class);
309
310     return ret;
311 }
312
313
314 static void __exit v3_exit(void) {
315     extern u32 pg_allocs;
316     extern u32 pg_frees;
317     extern u32 mallocs;
318     extern u32 frees;
319
320
321     // should probably try to stop any guests
322
323
324
325     dev_t dev = MKDEV(v3_major_num, MAX_VMS + 1);
326
327     INFO("Removing V3 Control device\n");
328
329
330     palacios_vmm_exit();
331
332     DEBUG("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
333     DEBUG("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
334
335     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
336
337     cdev_del(&ctrl_dev);
338
339     device_destroy(v3_class, dev);
340     class_destroy(v3_class);
341
342
343     deinit_lnx_extensions();
344
345     palacios_deinit_mm();
346
347     remove_proc_entry("v3-guests", dir);
348     remove_proc_entry("v3-mem", dir);
349     remove_proc_entry("v3vee", NULL);
350
351     DEBUG("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
352 }
353
354
355
356 module_init(v3_init);
357 module_exit(v3_exit);
358
359
360
361 void * trace_malloc(size_t size, gfp_t flags) {
362     void * addr = NULL;
363
364     mod_allocs++;
365     addr = kmalloc(size, flags);
366
367     return addr;
368 }
369
370
371 void trace_free(const void * objp) {
372     mod_frees++;
373     kfree(objp);
374 }