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 keyed stream support from monolithic embedding
[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-stream.h"
25 #include "palacios-file.h"
26 #include "palacios-serial.h"
27 #include "palacios-socket.h"
28 #include "palacios-vnet.h"
29 #include "palacios-packet.h"
30
31 #ifdef V3_CONFIG_EXT_INSPECTOR
32 #include "palacios-inspector.h"
33 #endif
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 void * v3_base_addr = NULL;
50 unsigned int v3_pages = 0;
51
52 static int register_vm( void ) {
53     int i, j = 0;
54     int avail = 0;
55
56     for (i = 0; i < sizeof(v3_minor_map); i++) {
57         if (v3_minor_map[i] != 0xff) {
58             for (j = 0; j < 8; j++) {
59                 if (!v3_minor_map[i] & (0x1 << j)) {
60                     avail = 1;
61                     v3_minor_map[i] |= (0x1 << j);
62                     break;
63                 }
64             }
65         
66             if (avail == 1) {
67                 break;
68             }
69         }
70     }
71
72     if (avail == 0) {
73         return -1;
74     }
75         
76     return (i * 8) + j;
77 }
78
79
80
81 static long v3_dev_ioctl(struct file * filp,
82                          unsigned int ioctl, unsigned long arg) {
83     void __user * argp = (void __user *)arg;
84     printk("V3 IOCTL %d\n", ioctl);
85
86
87     switch (ioctl) {
88         case V3_START_GUEST:{
89             int vm_minor = 0;
90             struct v3_guest_img user_image;
91             struct v3_guest * guest = kmalloc(sizeof(struct v3_guest), GFP_KERNEL);
92
93             if (IS_ERR(guest)) {
94                 printk("Error allocating Kernel guest_image\n");
95                 return -EFAULT;
96             }
97
98             memset(guest, 0, sizeof(struct v3_guest));
99
100             printk("Starting V3 Guest...\n");
101
102             vm_minor = register_vm();
103
104             if (vm_minor == -1) {
105                 printk("Too many VMs are currently running\n");
106                 return -EFAULT;
107             }
108
109             guest->vm_dev = MKDEV(v3_major_num, vm_minor);
110
111             if (copy_from_user(&user_image, argp, sizeof(struct v3_guest_img))) {
112                 printk("copy from user error getting guest image...\n");
113                 return -EFAULT;
114             }
115
116             guest->img_size = user_image.size;
117
118             printk("Allocating kernel memory for guest image (%llu bytes)\n", user_image.size);
119             guest->img = kmalloc(guest->img_size, GFP_KERNEL);
120
121             if (IS_ERR(guest->img)) {
122                 printk("Error: Could not allocate space for guest image\n");
123                 return -EFAULT;
124             }
125
126             if (copy_from_user(guest->img, user_image.guest_data, guest->img_size)) {
127                 printk("Error loading guest data\n");
128                 return -EFAULT;
129             }      
130
131             strncpy(guest->name, user_image.name, 127);
132
133             printk("Launching VM\n");
134
135             INIT_LIST_HEAD(&(guest->streams));
136             INIT_LIST_HEAD(&(guest->files));
137             INIT_LIST_HEAD(&(guest->sockets));
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 extern unsigned int v3_pages;
204 extern void * v3_base_addr;
205
206 static int __init v3_init(void) {
207     dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
208     int ret = 0;
209
210
211     palacios_init_mm();
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     if ((v3_pages > 0) && (v3_base_addr != NULL)) {
247         add_palacios_memory(__pa(v3_base_addr), v3_pages);
248     }
249
250     // Initialize Palacios
251     
252     palacios_vmm_init();
253
254 #ifdef V3_CONFIG_STREAM
255     palacios_init_stream();
256 #endif
257
258 #ifdef V3_CONFIG_FILE
259     palacios_file_init();
260 #endif
261
262 #ifdef V3_CONFIG_CONSOLE
263     palacios_init_console();
264 #endif
265
266 #ifdef V3_CONFIG_EXT_INSPECTOR
267     palacios_init_inspector();
268 #endif
269
270 #ifdef V3_CONFIG_SOCKET
271     palacios_socket_init();
272 #endif
273
274 #ifdef V3_CONFIG_PACKET
275     palacios_init_packet(NULL);
276 #endif
277
278 #ifdef V3_CONFIG_VNET
279     palacios_init_vnet();
280 #endif
281
282     return 0;
283
284  failure1:
285     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
286  failure2:
287     class_destroy(v3_class);
288
289     return ret;
290 }
291
292
293 static void __exit v3_exit(void) {
294     extern u32 pg_allocs;
295     extern u32 pg_frees;
296     extern u32 mallocs;
297     extern u32 frees;
298
299
300     // should probably try to stop any guests
301
302
303
304     dev_t dev = MKDEV(v3_major_num, MAX_VMS + 1);
305
306     printk("Removing V3 Control device\n");
307
308
309     palacios_vmm_exit();
310
311     printk("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
312     printk("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
313
314     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
315
316     cdev_del(&ctrl_dev);
317
318     device_destroy(v3_class, dev);
319     class_destroy(v3_class);
320
321
322
323 #ifdef V3_CONFIG_EXT_INSPECTOR
324     palacios_deinit_inspector();
325 #endif
326
327 #ifdef V3_CONFIG_FILE
328     palacios_file_deinit();
329 #endif
330
331 #ifdef V3_CONFIG_STREAM
332     palacios_deinit_stream();
333 #endif
334
335     palacios_deinit_mm();
336
337     printk("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
338 }
339
340
341
342 module_init(v3_init);
343 module_exit(v3_exit);
344
345
346
347 void * trace_malloc(size_t size, gfp_t flags) {
348     void * addr = NULL;
349
350     mod_allocs++;
351     addr = kmalloc(size, flags);
352
353     return addr;
354 }
355
356
357 void trace_free(const void * objp) {
358     mod_frees++;
359     kfree(objp);
360 }