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.


Merge branch 'devel' of palacios@newskysaw.cs.northwestern.edu:/home/palacios/palacio...
[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/errno.h>
9 #include <linux/percpu.h>
10 #include <linux/fs.h>
11 #include <linux/uaccess.h>
12 #include <linux/device.h>
13 #include <linux/cdev.h>
14
15 #include <linux/io.h>
16
17 #include <linux/file.h>
18 #include <linux/spinlock.h>
19 #include <linux/kthread.h>
20
21 #include "palacios.h"
22 #include "mm.h"
23 #include "vm.h"
24
25 #include "linux-exts.h"
26
27
28
29 MODULE_LICENSE("GPL");
30
31 int mod_allocs = 0;
32 int mod_frees = 0;
33
34
35 static int v3_major_num = 0;
36
37 static struct v3_guest * guest_map[MAX_VMS] = {[0 ... MAX_VMS - 1] = 0};
38
39 struct class * v3_class = NULL;
40 static struct cdev ctrl_dev;
41
42 static int register_vm(struct v3_guest * guest) {
43     int i = 0;
44
45     for (i = 0; i < MAX_VMS; i++) {
46         if (guest_map[i] == NULL) {
47             guest_map[i] = guest;
48             return i;
49         }
50     }
51
52     return -1;
53 }
54
55
56
57 static long v3_dev_ioctl(struct file * filp,
58                          unsigned int ioctl, unsigned long arg) {
59     void __user * argp = (void __user *)arg;
60     printk("V3 IOCTL %d\n", ioctl);
61
62
63     switch (ioctl) {
64         case V3_START_GUEST:{
65             int vm_minor = 0;
66             struct v3_guest_img user_image;
67             struct v3_guest * guest = kmalloc(sizeof(struct v3_guest), GFP_KERNEL);
68
69             if (IS_ERR(guest)) {
70                 printk("Error allocating Kernel guest_image\n");
71                 return -EFAULT;
72             }
73
74             memset(guest, 0, sizeof(struct v3_guest));
75
76             printk("Starting V3 Guest... (%p)\n", guest);
77
78             vm_minor = register_vm(guest);
79
80             if (vm_minor == -1) {
81                 printk("Too many VMs are currently running\n");
82                 return -EFAULT;
83             }
84
85             guest->vm_dev = MKDEV(v3_major_num, vm_minor);
86
87             if (copy_from_user(&user_image, argp, sizeof(struct v3_guest_img))) {
88                 printk("copy from user error getting guest image...\n");
89                 return -EFAULT;
90             }
91
92             guest->img_size = user_image.size;
93
94             printk("Allocating kernel memory for guest image (%llu bytes)\n", user_image.size);
95             guest->img = vmalloc(guest->img_size);
96
97             if (IS_ERR(guest->img)) {
98                 printk("Error: Could not allocate space for guest image\n");
99                 return -EFAULT;
100             }
101
102             if (copy_from_user(guest->img, user_image.guest_data, guest->img_size)) {
103                 printk("Error loading guest data\n");
104                 return -EFAULT;
105             }      
106
107             strncpy(guest->name, user_image.name, 127);
108
109             printk("Launching VM\n");
110
111             INIT_LIST_HEAD(&(guest->exts));
112
113             init_completion(&(guest->start_done));
114             init_completion(&(guest->thread_done));
115
116             { 
117                 struct task_struct * launch_thread = NULL;
118                 // At some point we're going to want to allow the user to specify a CPU mask
119                 // But for now, well just launch from the local core, and rely on the global cpu mask
120
121                 preempt_disable();
122                 launch_thread = kthread_create(start_palacios_vm, guest, guest->name);
123                 
124                 if (IS_ERR(launch_thread)) {
125                     preempt_enable();
126                     printk("Palacios error creating launch thread for vm (%s)\n", guest->name);
127                     return -EFAULT;
128                 }
129
130                 kthread_bind(launch_thread, smp_processor_id());
131                 preempt_enable();
132
133                 wake_up_process(launch_thread);
134             }
135
136             wait_for_completion(&(guest->start_done));
137
138             return guest->vm_dev;
139             break;
140         }
141         case V3_STOP_GUEST: {
142             unsigned long vm_idx = arg;
143             struct v3_guest * guest = guest_map[vm_idx];
144
145             printk("Stopping VM idx=%d\n", vm_idx);
146             printk("Stopping VM (%s) (%p)\n", guest->name, guest);
147
148
149             if (irqs_disabled()) {
150                 printk("WHAT!!?? IRQs are disabled??\n");
151                 break;
152             }
153
154             stop_palacios_vm(guest);
155             guest_map[vm_idx] = NULL;
156             break;
157         }
158         case V3_ADD_MEMORY: {
159             struct v3_mem_region mem;
160             
161             memset(&mem, 0, sizeof(struct v3_mem_region));
162             
163             if (copy_from_user(&mem, argp, sizeof(struct v3_mem_region))) {
164                 printk("copy from user error getting mem_region...\n");
165                 return -EFAULT;
166             }
167
168             printk("Adding %llu pages to Palacios memory\n", mem.num_pages);
169
170             if (add_palacios_memory(mem.base_addr, mem.num_pages) == -1) {
171                 printk("Error adding memory to Palacios\n");
172                 return -EFAULT;
173             }
174
175             break;
176         }
177
178         default: 
179             printk("\tUnhandled\n");
180             return -EINVAL;
181     }
182
183     return 0;
184 }
185
186
187
188 static struct file_operations v3_ctrl_fops = {
189     .owner = THIS_MODULE,
190     .unlocked_ioctl = v3_dev_ioctl,
191     .compat_ioctl = v3_dev_ioctl,
192 };
193
194
195
196 static int __init v3_init(void) {
197     dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
198     int ret = 0;
199
200
201     palacios_init_mm();
202
203
204     // Initialize Palacios
205     
206     palacios_vmm_init();
207
208
209     // initialize extensions
210     init_lnx_extensions();
211
212
213     v3_class = class_create(THIS_MODULE, "vms");
214     if (IS_ERR(v3_class)) {
215         printk("Failed to register V3 VM device class\n");
216         return PTR_ERR(v3_class);
217     }
218
219     printk("intializing V3 Control device\n");
220
221     ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee");
222
223     if (ret < 0) {
224         printk("Error registering device region for V3 devices\n");
225         goto failure2;
226     }
227
228     v3_major_num = MAJOR(dev);
229
230     dev = MKDEV(v3_major_num, MAX_VMS + 1);
231
232     
233     printk("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev));
234     cdev_init(&ctrl_dev, &v3_ctrl_fops);
235     ctrl_dev.owner = THIS_MODULE;
236     ctrl_dev.ops = &v3_ctrl_fops;
237     cdev_add(&ctrl_dev, dev, 1);
238     
239     device_create(v3_class, NULL, dev, NULL, "v3vee");
240
241     if (ret != 0) {
242         printk("Error adding v3 control device\n");
243         goto failure1;
244     }
245
246
247
248     return 0;
249
250  failure1:
251     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
252  failure2:
253     class_destroy(v3_class);
254
255     return ret;
256 }
257
258
259 static void __exit v3_exit(void) {
260     extern u32 pg_allocs;
261     extern u32 pg_frees;
262     extern u32 mallocs;
263     extern u32 frees;
264
265
266     // should probably try to stop any guests
267
268
269
270     dev_t dev = MKDEV(v3_major_num, MAX_VMS + 1);
271
272     printk("Removing V3 Control device\n");
273
274
275     palacios_vmm_exit();
276
277     printk("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
278     printk("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
279
280     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
281
282     cdev_del(&ctrl_dev);
283
284     device_destroy(v3_class, dev);
285     class_destroy(v3_class);
286
287
288     deinit_lnx_extensions();
289
290     palacios_deinit_mm();
291
292     printk("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
293 }
294
295
296
297 module_init(v3_init);
298 module_exit(v3_exit);
299
300
301
302 void * trace_malloc(size_t size, gfp_t flags) {
303     void * addr = NULL;
304
305     mod_allocs++;
306     addr = kmalloc(size, flags);
307
308     return addr;
309 }
310
311
312 void trace_free(const void * objp) {
313     mod_frees++;
314     kfree(objp);
315 }