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.


231a7f9b8392eea15362069f443a43fb7ab47d53
[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 #ifdef V3_CONFIG_KEYED_STREAMS
36 #include "palacios-keyed-stream.h"
37 #endif
38
39
40 MODULE_LICENSE("GPL");
41
42 int mod_allocs = 0;
43 int mod_frees = 0;
44
45
46 static int v3_major_num = 0;
47
48 static u8 v3_minor_map[MAX_VMS / 8] = {[0 ... (MAX_VMS / 8) - 1] = 0}; 
49
50
51 struct class * v3_class = NULL;
52 static struct cdev ctrl_dev;
53
54 void * v3_base_addr = NULL;
55 unsigned int v3_pages = 0;
56
57 static int register_vm( void ) {
58     int i, j = 0;
59     int avail = 0;
60
61     for (i = 0; i < sizeof(v3_minor_map); i++) {
62         if (v3_minor_map[i] != 0xff) {
63             for (j = 0; j < 8; j++) {
64                 if (!v3_minor_map[i] & (0x1 << j)) {
65                     avail = 1;
66                     v3_minor_map[i] |= (0x1 << j);
67                     break;
68                 }
69             }
70         
71             if (avail == 1) {
72                 break;
73             }
74         }
75     }
76
77     if (avail == 0) {
78         return -1;
79     }
80         
81     return (i * 8) + j;
82 }
83
84
85
86 static long v3_dev_ioctl(struct file * filp,
87                          unsigned int ioctl, unsigned long arg) {
88     void __user * argp = (void __user *)arg;
89     printk("V3 IOCTL %d\n", ioctl);
90
91
92     switch (ioctl) {
93         case V3_START_GUEST:{
94             int vm_minor = 0;
95             struct v3_guest_img user_image;
96             struct v3_guest * guest = kmalloc(sizeof(struct v3_guest), GFP_KERNEL);
97
98             if (IS_ERR(guest)) {
99                 printk("Error allocating Kernel guest_image\n");
100                 return -EFAULT;
101             }
102
103             memset(guest, 0, sizeof(struct v3_guest));
104
105             printk("Starting V3 Guest...\n");
106
107             vm_minor = register_vm();
108
109             if (vm_minor == -1) {
110                 printk("Too many VMs are currently running\n");
111                 return -EFAULT;
112             }
113
114             guest->vm_dev = MKDEV(v3_major_num, vm_minor);
115
116             if (copy_from_user(&user_image, argp, sizeof(struct v3_guest_img))) {
117                 printk("copy from user error getting guest image...\n");
118                 return -EFAULT;
119             }
120
121             guest->img_size = user_image.size;
122
123             printk("Allocating kernel memory for guest image (%llu bytes)\n", user_image.size);
124             guest->img = kmalloc(guest->img_size, GFP_KERNEL);
125
126             if (IS_ERR(guest->img)) {
127                 printk("Error: Could not allocate space for guest image\n");
128                 return -EFAULT;
129             }
130
131             if (copy_from_user(guest->img, user_image.guest_data, guest->img_size)) {
132                 printk("Error loading guest data\n");
133                 return -EFAULT;
134             }      
135
136             strncpy(guest->name, user_image.name, 127);
137
138             printk("Launching VM\n");
139
140             INIT_LIST_HEAD(&(guest->streams));
141             INIT_LIST_HEAD(&(guest->files));
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 extern unsigned int v3_pages;
212 extern void * v3_base_addr;
213
214 static int __init v3_init(void) {
215     dev_t dev = MKDEV(0, 0); // We dynamicallly assign the major number
216     int ret = 0;
217
218
219     palacios_init_mm();
220
221     v3_class = class_create(THIS_MODULE, "vms");
222     if (IS_ERR(v3_class)) {
223         printk("Failed to register V3 VM device class\n");
224         return PTR_ERR(v3_class);
225     }
226
227     printk("intializing V3 Control device\n");
228
229     ret = alloc_chrdev_region(&dev, 0, MAX_VMS + 1, "v3vee");
230
231     if (ret < 0) {
232         printk("Error registering device region for V3 devices\n");
233         goto failure2;
234     }
235
236     v3_major_num = MAJOR(dev);
237
238     dev = MKDEV(v3_major_num, MAX_VMS + 1);
239
240     
241     printk("Creating V3 Control device: Major %d, Minor %d\n", v3_major_num, MINOR(dev));
242     cdev_init(&ctrl_dev, &v3_ctrl_fops);
243     ctrl_dev.owner = THIS_MODULE;
244     ctrl_dev.ops = &v3_ctrl_fops;
245     cdev_add(&ctrl_dev, dev, 1);
246     
247     device_create(v3_class, NULL, dev, NULL, "v3vee");
248
249     if (ret != 0) {
250         printk("Error adding v3 control device\n");
251         goto failure1;
252     }
253
254     if ((v3_pages > 0) && (v3_base_addr != NULL)) {
255         add_palacios_memory(__pa(v3_base_addr), v3_pages);
256     }
257
258     // Initialize Palacios
259     
260     palacios_vmm_init();
261
262 #ifdef V3_CONFIG_STREAM
263     palacios_init_stream();
264 #endif
265
266 #ifdef V3_CONFIG_FILE
267     palacios_file_init();
268 #endif
269
270 #ifdef V3_CONFIG_KEYED_STREAMS
271     palacios_init_keyed_streams();
272 #endif
273
274 #ifdef V3_CONFIG_CONSOLE
275     palacios_init_console();
276 #endif
277
278 #ifdef V3_CONFIG_GRAPHICS_CONSOLE
279     palacios_init_graphics_console();
280 #endif
281
282 #ifdef V3_CONFIG_EXT_INSPECTOR
283     palacios_init_inspector();
284 #endif
285
286 #ifdef V3_CONFIG_SOCKET
287     palacios_socket_init();
288 #endif
289
290 #ifdef V3_CONFIG_PACKET
291     palacios_init_packet(NULL);
292 #endif
293
294 #ifdef V3_CONFIG_VNET
295     palacios_vnet_init();
296 #endif
297
298 #ifdef V3_CONFIG_HOST_DEVICE
299     palacios_init_host_dev();
300 #endif
301
302     return 0;
303
304  failure1:
305     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
306  failure2:
307     class_destroy(v3_class);
308
309     return ret;
310 }
311
312
313 static void __exit v3_exit(void) {
314     extern u32 pg_allocs;
315     extern u32 pg_frees;
316     extern u32 mallocs;
317     extern u32 frees;
318
319
320     // should probably try to stop any guests
321
322
323
324     dev_t dev = MKDEV(v3_major_num, MAX_VMS + 1);
325
326     printk("Removing V3 Control device\n");
327
328
329     palacios_vmm_exit();
330
331     printk("Palacios Mallocs = %d, Frees = %d\n", mallocs, frees);
332     printk("Palacios Page Allocs = %d, Page Frees = %d\n", pg_allocs, pg_frees);
333
334     unregister_chrdev_region(MKDEV(v3_major_num, 0), MAX_VMS + 1);
335
336     cdev_del(&ctrl_dev);
337
338     device_destroy(v3_class, dev);
339     class_destroy(v3_class);
340
341
342
343 #ifdef V3_CONFIG_EXT_INSPECTOR
344     palacios_deinit_inspector();
345 #endif
346
347 #ifdef V3_CONFIG_FILE
348     palacios_file_deinit();
349 #endif
350
351 #ifdef V3_CONFIG_STREAM
352     palacios_deinit_stream();
353 #endif
354
355     palacios_deinit_mm();
356
357     printk("Palacios Module Mallocs = %d, Frees = %d\n", mod_allocs, mod_frees);
358 }
359
360
361
362 module_init(v3_init);
363 module_exit(v3_exit);
364
365
366
367 void * trace_malloc(size_t size, gfp_t flags) {
368     void * addr = NULL;
369
370     mod_allocs++;
371     addr = kmalloc(size, flags);
372
373     return addr;
374 }
375
376
377 void trace_free(const void * objp) {
378     mod_frees++;
379     kfree(objp);
380 }