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