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.


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