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.


e3f83b6988169c1dde2d2a075685de9174001978
[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 CONFIG_DEBUG_FS
32 #include "palacios-debugfs.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             kthread_run(start_palacios_vm, guest, guest->name);
142
143             wait_for_completion(&(guest->start_done));
144
145             return guest->vm_dev;
146             break;
147         }
148         case V3_ADD_MEMORY: {
149             struct v3_mem_region mem;
150             
151             memset(&mem, 0, sizeof(struct v3_mem_region));
152             
153             if (copy_from_user(&mem, argp, sizeof(struct v3_mem_region))) {
154                 printk("copy from user error getting mem_region...\n");
155                 return -EFAULT;
156             }
157
158             printk("Adding %llu pages to Palacios memory\n", mem.num_pages);
159
160             if (add_palacios_memory(mem.base_addr, mem.num_pages) == -1) {
161                 printk("Error adding memory to Palacios\n");
162                 return -EFAULT;
163             }
164
165             // Mem test...
166             /*
167               {
168               void * vaddr = __va(alloc_palacios_pgs(131072, 4096));
169               memset(vaddr, 0xfe492fe2, mem.num_pages * 4096);
170               }
171             */
172
173             break;
174         }
175
176         case V3_START_NETWORK: {
177             struct v3_network net;
178             memset(&net, 0, sizeof(struct v3_network));
179    
180             if(copy_from_user(&net, argp, sizeof(struct v3_network))){
181                 printk("copy from user error getting network service requests ... \n");
182                 return -EFAULT;
183             }
184  
185         #ifdef CONFIG_PALACIOS_SOCKET
186             if(net.socket == 1){
187                 palacios_socket_init();
188                 printk("Started Palacios Socket\n");
189             }
190         #endif
191         #ifdef CONFIG_PALACIOS_PACKET
192             if(net.packet == 1){
193                 palacios_init_packet(NULL);
194                 printk("Started Palacios Direct Network Bridge\n");
195             }
196         #endif
197         #ifdef CONFIG_PALACIOS_VNET
198             if(net.vnet == 1){
199                 palacios_init_vnet();
200                 printk("Started Palacios VNET Service\n");
201             }
202         #endif
203  
204             break;
205         }
206         default: 
207             printk("\tUnhandled\n");
208             return -EINVAL;
209     }
210
211     return 0;
212 }
213
214
215
216 static struct file_operations v3_ctrl_fops = {
217     .owner = THIS_MODULE,
218     .unlocked_ioctl = v3_dev_ioctl,
219     .compat_ioctl = v3_dev_ioctl,
220 };
221
222
223 extern unsigned int v3_pages;
224 extern void * v3_base_addr;
225
226 static int __init v3_init(void) {
227     dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
228     int ret = 0;
229
230
231     palacios_init_mm();
232
233     v3_class = class_create(THIS_MODULE, "vms");
234     if (IS_ERR(v3_class)) {
235         printk("Failed to register V3 VM device class\n");
236         return PTR_ERR(v3_class);
237     }
238
239     printk("intializing V3 Control device\n");
240
241     ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee");
242
243     if (ret < 0) {
244         printk("Error registering device region for V3 devices\n");
245         goto failure2;
246     }
247
248     v3_major_num = MAJOR(dev);
249
250     dev = MKDEV(v3_major_num, MAX_VMS + 1);
251
252     
253     printk("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev));
254     cdev_init(&ctrl_dev, &v3_ctrl_fops);
255     ctrl_dev.owner = THIS_MODULE;
256     ctrl_dev.ops = &v3_ctrl_fops;
257     cdev_add(&ctrl_dev, dev, 1);
258     
259     device_create(v3_class, NULL, dev, NULL, "v3vee");
260
261     if (ret != 0) {
262         printk("Error adding v3 control device\n");
263         goto failure1;
264     }
265
266     if ((v3_pages > 0) && (v3_base_addr != NULL)) {
267         add_palacios_memory(__pa(v3_base_addr), v3_pages);
268     }
269
270     // Initialize Palacios
271     
272     palacios_vmm_init();
273
274     palacios_init_stream();
275     palacios_file_init();
276     palacios_init_console();
277
278
279 #ifdef CONFIG_DEBUG_FS
280     palacios_init_debugfs();
281 #endif
282
283     return 0;
284
285  failure1:
286     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
287  failure2:
288     class_destroy(v3_class);
289
290     return ret;
291 }
292
293
294 static void __exit v3_exit(void) {
295     extern u32 pg_allocs;
296     extern u32 pg_frees;
297     extern u32 mallocs;
298     extern u32 frees;
299
300
301     // should probably try to stop any guests
302
303
304
305     dev_t dev = MKDEV(v3_major_num, MAX_VMS + 1);
306
307     printk("Removing V3 Control device\n");
308
309
310     palacios_vmm_exit();
311
312     printk("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
313     printk("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
314
315     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
316
317     cdev_del(&ctrl_dev);
318
319     device_destroy(v3_class, dev);
320     class_destroy(v3_class);
321
322
323
324 #ifdef CONFIG_DEBUG_FS
325     palacios_deinit_debugfs();
326 #endif
327
328     palacios_file_deinit();
329     palacios_deinit_stream();
330
331     palacios_deinit_mm();
332
333     printk("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
334 }
335
336
337
338 module_init(v3_init);
339 module_exit(v3_exit);
340
341
342
343 void * trace_malloc(size_t size, gfp_t flags) {
344     void * addr = NULL;
345
346     mod_allocs++;
347     addr = kmalloc(size, flags);
348
349     return addr;
350 }
351
352
353 void trace_free(const void * objp) {
354     mod_frees++;
355     kfree(objp);
356 }