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.


Use of information interface to enhance output of /proc/v3vee-/v3-guests in Linux
[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
228 #define MAX_VCORES 32
229
230 static int read_guests(char * buf, char ** start, off_t off, int count,
231                        int * eof, void * data)
232 {
233     int len = 0;
234     unsigned int i = 0;
235
236     struct v3_vm_state *s =palacios_alloc(sizeof(struct v3_vm_state)+MAX_VCORES*sizeof(struct v3_vcore_state));
237     
238     if (!s) { 
239       ERROR("No space for state structure\n");
240       goto out;
241     }
242     
243     for(i = 0; i < MAX_VMS; i++) {
244       if (guest_map[i] != NULL) {
245         if (len>=count) { 
246           goto out;
247         } else {
248           len += snprintf(buf+len, count-len,
249                           "%s\t/dev/v3-vm%d ", 
250                           guest_map[i]->name, i);
251           
252           if (len>=count) { 
253             *(buf+len-1)='\n';
254             goto out;
255           } else {
256             // Get extended data
257             s->num_vcores=MAX_VCORES; // max we can handle
258             if (v3_get_state_vm(guest_map[i]->v3_ctx, s)) {
259               ERROR("Cannot get VM info\n");
260               *(buf+len-1)='\n';
261               goto out;
262             } else {
263               unsigned long j;
264
265               len+=snprintf(buf+len, count-len,
266                             "%s [0x%p-0x%p] %lu vcores ",
267                             s->state==V3_VM_INVALID ? "INVALID" :
268                             s->state==V3_VM_RUNNING ? "running" :
269                             s->state==V3_VM_STOPPED ? "stopped" :
270                             s->state==V3_VM_PAUSED ? "paused" :
271                             s->state==V3_VM_ERROR ? "ERROR" :
272                             s->state==V3_VM_SIMULATING ? "simulating" : "UNKNOWN",
273                             s->mem_base_paddr, s->mem_base_paddr+s->mem_size-1,
274                             s->num_vcores);
275               if (len>=count) { 
276                 *(buf+len-1)='\n';
277                 goto out;
278               }
279               for (j=0;j<s->num_vcores;j++) {
280                 len+=snprintf(buf+len, count-len,
281                               "[vcore %lu %s on pcore %lu %llu exits rip=0x%p %s %s %s] ",
282                               j, 
283                               s->vcore[j].state==V3_VCORE_INVALID ? "INVALID" :
284                               s->vcore[j].state==V3_VCORE_RUNNING ? "running" :
285                               s->vcore[j].state==V3_VCORE_STOPPED ? "stopped" : "UNKNOWN",
286                               s->vcore[j].pcore,
287                               s->vcore[j].num_exits,
288                               s->vcore[j].last_rip,
289                               s->vcore[j].cpu_mode==V3_VCORE_CPU_REAL ? "real" :
290                               s->vcore[j].cpu_mode==V3_VCORE_CPU_PROTECTED ? "protected" :
291                               s->vcore[j].cpu_mode==V3_VCORE_CPU_PROTECTED_PAE ? "protectedpae" :
292                               s->vcore[j].cpu_mode==V3_VCORE_CPU_LONG ? "long" :
293                               s->vcore[j].cpu_mode==V3_VCORE_CPU_LONG_32_COMPAT ? "long32" :
294                               s->vcore[j].cpu_mode==V3_VCORE_CPU_LONG_16_COMPAT ? "long16" : "UNKNOWN",
295                               s->vcore[j].mem_mode==V3_VCORE_MEM_MODE_PHYSICAL ? "physical" :
296                               s->vcore[j].mem_mode==V3_VCORE_MEM_MODE_VIRTUAL ? "virtual" : "UNKNOWN",
297                               s->vcore[j].mem_state==V3_VCORE_MEM_STATE_SHADOW ? "shadow" :
298                               s->vcore[j].mem_state==V3_VCORE_MEM_STATE_NESTED ? "nested" : "UNKNOWN");
299                 if (len>=count) {
300                   *(buf+len-1)='\n';
301                   goto out;
302                 }
303               }
304
305               *(buf+len-1)='\n';
306
307             }
308           }
309         }
310       }
311     }
312  
313  out:
314     if (s) { palacios_free(s); }
315
316     return len;
317 }
318
319 static int show_mem(char * buf, char ** start, off_t off, int count,
320                     int * eof, void * data)
321 {
322     int len = 0;
323     
324     len = snprintf(buf,count, "%p\n", (void *)get_palacios_base_addr());
325     len += snprintf(buf+len,count-len, "%lld\n", get_palacios_num_pages());
326     
327     return len;
328 }
329
330
331 static int __init v3_init(void) {
332     dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
333     int ret = 0;
334
335
336     palacios_init_mm();
337
338     // Initialize Palacios
339     palacios_vmm_init();
340
341
342     // initialize extensions
343     init_lnx_extensions();
344
345
346     v3_class = class_create(THIS_MODULE, "vms");
347     if (IS_ERR(v3_class)) {
348         ERROR("Failed to register V3 VM device class\n");
349         return PTR_ERR(v3_class);
350     }
351
352     INFO("intializing V3 Control device\n");
353
354     ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee");
355
356     if (ret < 0) {
357         ERROR("Error registering device region for V3 devices\n");
358         goto failure2;
359     }
360
361     v3_major_num = MAJOR(dev);
362
363     dev = MKDEV(v3_major_num, MAX_VMS + 1);
364
365     
366     DEBUG("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev));
367     cdev_init(&ctrl_dev, &v3_ctrl_fops);
368     ctrl_dev.owner = THIS_MODULE;
369     ctrl_dev.ops = &v3_ctrl_fops;
370     cdev_add(&ctrl_dev, dev, 1);
371     
372     device_create(v3_class, NULL, dev, NULL, "v3vee");
373
374     if (ret != 0) {
375         ERROR("Error adding v3 control device\n");
376         goto failure1;
377     }
378
379     dir = proc_mkdir("v3vee", NULL);
380     if(dir) {
381         struct proc_dir_entry *entry;
382
383         entry = create_proc_read_entry("v3-guests", 0444, dir, 
384                                        read_guests, NULL);
385         if (entry) {
386             INFO("/proc/v3vee/v3-guests successfully created\n");
387         } else {
388             ERROR("Could not create proc entry\n");
389             goto failure1;
390         }
391         
392         entry = create_proc_read_entry("v3-mem", 0444, dir,
393                                        show_mem, NULL);
394         if (entry) {
395             INFO("/proc/v3vee/v3-mem successfully added\n");
396         } else {
397             ERROR("Could not create proc entry\n");
398             goto failure1;
399         }
400     } else {
401         ERROR("Could not create proc entry\n");
402         goto failure1;
403     }
404         
405     return 0;
406
407  failure1:
408     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
409  failure2:
410     class_destroy(v3_class);
411
412     return ret;
413 }
414
415
416 static void __exit v3_exit(void) {
417     extern u32 pg_allocs;
418     extern u32 pg_frees;
419     extern u32 mallocs;
420     extern u32 frees;
421     int i = 0;
422     struct v3_guest * guest;
423     dev_t dev;
424
425
426     /* Stop and free any running VMs */ 
427     for (i = 0; i < MAX_VMS; i++) {
428         if (guest_map[i] != NULL) {
429                 guest = (struct v3_guest *)guest_map[i];
430
431                 if (v3_stop_vm(guest->v3_ctx) < 0) 
432                         ERROR("Couldn't stop VM %d\n", i);
433
434                 free_palacios_vm(guest);
435                 guest_map[i] = NULL;
436         }
437     }
438
439     dev = MKDEV(v3_major_num, MAX_VMS + 1);
440
441     INFO("Removing V3 Control device\n");
442
443
444     palacios_vmm_exit();
445
446     DEBUG("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
447     DEBUG("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
448
449     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
450
451     cdev_del(&ctrl_dev);
452
453     device_destroy(v3_class, dev);
454     class_destroy(v3_class);
455
456
457     deinit_lnx_extensions();
458
459     palacios_deinit_mm();
460
461     remove_proc_entry("v3-guests", dir);
462     remove_proc_entry("v3-mem", dir);
463     remove_proc_entry("v3vee", NULL);
464
465     DEBUG("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
466 }
467
468
469
470 module_init(v3_init);
471 module_exit(v3_exit);
472
473
474
475 void * trace_malloc(size_t size, gfp_t flags) {
476     void * addr = NULL;
477
478     mod_allocs++;
479     addr = kmalloc(size, flags);
480
481     return addr;
482 }
483
484
485 void trace_free(const void * objp) {
486     mod_frees++;
487     kfree(objp);
488 }