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.


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