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.


merge VNET Linux backend code into Linux module directory
[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 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 void * v3_base_addr = NULL;
46 unsigned int v3_pages = 0;
47
48 static int register_vm( void ) {
49     int i, j = 0;
50     int avail = 0;
51
52     for (i = 0; i < sizeof(v3_minor_map); i++) {
53         if (v3_minor_map[i] != 0xff) {
54             for (j = 0; j < 8; j++) {
55                 if (!v3_minor_map[i] & (0x1 << j)) {
56                     avail = 1;
57                     v3_minor_map[i] |= (0x1 << j);
58                     break;
59                 }
60             }
61         
62             if (avail == 1) {
63                 break;
64             }
65         }
66     }
67
68     if (avail == 0) {
69         return -1;
70     }
71         
72     return (i * 8) + j;
73 }
74
75
76
77 static long v3_dev_ioctl(struct file * filp,
78                          unsigned int ioctl, unsigned long arg) {
79     void __user * argp = (void __user *)arg;
80     printk("V3 IOCTL %d\n", ioctl);
81
82
83     switch (ioctl) {
84         case V3_START_GUEST:{
85             int vm_minor = 0;
86             struct v3_guest_img user_image;
87             struct v3_guest * guest = kmalloc(sizeof(struct v3_guest), GFP_KERNEL);
88
89             if (IS_ERR(guest)) {
90                 printk("Error allocating Kernel guest_image\n");
91                 return -EFAULT;
92             }
93
94             memset(guest, 0, sizeof(struct v3_guest));
95
96             printk("Starting V3 Guest...\n");
97
98             vm_minor = register_vm();
99
100             if (vm_minor == -1) {
101                 printk("Too many VMs are currently running\n");
102                 return -EFAULT;
103             }
104
105             guest->vm_dev = MKDEV(v3_major_num, vm_minor);
106
107             if (copy_from_user(&user_image, argp, sizeof(struct v3_guest_img))) {
108                 printk("copy from user error getting guest image...\n");
109                 return -EFAULT;
110             }
111
112             guest->img_size = user_image.size;
113
114             printk("Allocating kernel memory for guest image (%llu bytes)\n", user_image.size);
115             guest->img = kmalloc(guest->img_size, GFP_KERNEL);
116
117             if (IS_ERR(guest->img)) {
118                 printk("Error: Could not allocate space for guest image\n");
119                 return -EFAULT;
120             }
121
122             if (copy_from_user(guest->img, user_image.guest_data, guest->img_size)) {
123                 printk("Error loading guest data\n");
124                 return -EFAULT;
125             }      
126
127             strncpy(guest->name, user_image.name, 127);
128
129             printk("Launching VM\n");
130
131             INIT_LIST_HEAD(&(guest->streams));
132             INIT_LIST_HEAD(&(guest->files));
133             INIT_LIST_HEAD(&(guest->sockets));
134             init_completion(&(guest->start_done));
135             init_completion(&(guest->thread_done));
136
137             kthread_run(start_palacios_vm, guest, guest->name);
138
139             wait_for_completion(&(guest->start_done));
140
141             return guest->vm_dev;
142             break;
143         }
144         case V3_ADD_MEMORY: {
145             struct v3_mem_region mem;
146             
147             memset(&mem, 0, sizeof(struct v3_mem_region));
148             
149             if (copy_from_user(&mem, argp, sizeof(struct v3_mem_region))) {
150                 printk("copy from user error getting mem_region...\n");
151                 return -EFAULT;
152             }
153
154             printk("Adding %llu pages to Palacios memory\n", mem.num_pages);
155
156             if (add_palacios_memory(mem.base_addr, mem.num_pages) == -1) {
157                 printk("Error adding memory to Palacios\n");
158                 return -EFAULT;
159             }
160
161             // Mem test...
162             /*
163               {
164               void * vaddr = __va(alloc_palacios_pgs(131072, 4096));
165               memset(vaddr, 0xfe492fe2, mem.num_pages * 4096);
166               }
167             */
168
169             break;
170         }
171
172         case V3_START_NETWORK: {
173             struct v3_network net;
174             memset(&net, 0, sizeof(struct v3_network));
175    
176             if(copy_from_user(&net, argp, sizeof(struct v3_network))){
177                 printk("copy from user error getting network service requests ... \n");
178                 return -EFAULT;
179             }
180  
181         #ifdef CONFIG_PALACIOS_SOCKET
182             if(net.socket == 1){
183                 palacios_socket_init();
184                 printk("Started Palacios Socket\n");
185             }
186         #endif
187         #ifdef CONFIG_PALACIOS_PACKET
188             if(net.packet == 1){
189                 palacios_init_packet(NULL);
190                 printk("Started Palacios Direct Network Bridge\n");
191             }
192         #endif
193         #ifdef CONFIG_PALACIOS_VNET
194             if(net.vnet == 1){
195                 palacios_init_vnet();
196                 printk("Started Palacios VNET Service\n");
197             }
198         #endif
199  
200             break;
201         }
202         default: 
203             printk("\tUnhandled\n");
204             return -EINVAL;
205     }
206
207     return 0;
208 }
209
210
211
212 static struct file_operations v3_ctrl_fops = {
213     .owner = THIS_MODULE,
214     .unlocked_ioctl = v3_dev_ioctl,
215     .compat_ioctl = v3_dev_ioctl,
216 };
217
218
219 extern unsigned int v3_pages;
220 extern void * v3_base_addr;
221
222 static int __init v3_init(void) {
223     dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
224     int ret = 0;
225
226
227     palacios_init_mm();
228
229     v3_class = class_create(THIS_MODULE, "vms");
230     if (IS_ERR(v3_class)) {
231         printk("Failed to register V3 VM device class\n");
232         return PTR_ERR(v3_class);
233     }
234
235     printk("intializing V3 Control device\n");
236
237     ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee");
238
239     if (ret < 0) {
240         printk("Error registering device region for V3 devices\n");
241         goto failure2;
242     }
243
244     v3_major_num = MAJOR(dev);
245
246     dev = MKDEV(v3_major_num, MAX_VMS + 1);
247
248     
249     printk("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev));
250     cdev_init(&ctrl_dev, &v3_ctrl_fops);
251     ctrl_dev.owner = THIS_MODULE;
252     ctrl_dev.ops = &v3_ctrl_fops;
253     cdev_add(&ctrl_dev, dev, 1);
254     
255     device_create(v3_class, NULL, dev, NULL, "v3vee");
256
257     if (ret != 0) {
258         printk("Error adding v3 control device\n");
259         goto failure1;
260     }
261
262     if ((v3_pages > 0) && (v3_base_addr != NULL)) {
263         add_palacios_memory(__pa(v3_base_addr), v3_pages);
264     }
265
266     // Initialize Palacios
267     
268     palacios_vmm_init();
269
270     palacios_init_stream();
271     palacios_file_init();
272     palacios_init_console();
273
274     return 0;
275
276  failure1:
277     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
278  failure2:
279     class_destroy(v3_class);
280
281     return ret;
282 }
283
284
285 static void __exit v3_exit(void) {
286     extern u32 pg_allocs;
287     extern u32 pg_frees;
288     extern u32 mallocs;
289     extern u32 frees;
290
291
292     // should probably try to stop any guests
293
294
295
296     dev_t dev = MKDEV(v3_major_num, MAX_VMS + 1);
297
298     printk("Removing V3 Control device\n");
299
300
301     palacios_vmm_exit();
302
303     printk("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
304     printk("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
305
306     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
307
308     cdev_del(&ctrl_dev);
309
310     device_destroy(v3_class, dev);
311     class_destroy(v3_class);
312
313
314     palacios_file_deinit();
315     palacios_deinit_stream();
316
317     palacios_deinit_mm();
318
319     printk("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
320 }
321
322
323
324 module_init(v3_init);
325 module_exit(v3_exit);
326
327
328
329 void * trace_malloc(size_t size, gfp_t flags) {
330     void * addr = NULL;
331
332     mod_allocs++;
333     addr = kmalloc(size, flags);
334
335     return addr;
336 }
337
338
339 void trace_free(const void * objp) {
340     mod_frees++;
341     kfree(objp);
342 }