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.


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