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.


Device File Virtualization Proof of Concept (Kernel+Preload)
[palacios.git] / gears / services / devfile / devfile_host.c
1 /* 
2    Device File Virtualization Host Module 
3
4    (c) Akhil Guliani and William Gross, 2015
5      
6    Adapted from MPI module (c) 2012 Peter Dinda
7
8  */
9 #include <linux/fs.h>
10 #include <linux/namei.h>
11 #include <linux/version.h>
12 #include <linux/file.h>
13 #include <linux/spinlock.h>
14 #include <linux/uaccess.h>
15 #include <linux/module.h>
16
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
19 #include <linux/mm.h>
20 #include <linux/sched.h>
21
22 #include <linux/syscalls.h>
23 #include <linux/init.h>
24 #include <linux/kmod.h>
25 #include <linux/delay.h>
26 #include <linux/wait.h>
27 #include <linux/poll.h>
28
29 #include <linux/file.h>
30 #include <linux/fcntl.h>
31 #include <linux/device.h>
32 #include <linux/cdev.h>
33
34 #include <asm/uaccess.h>
35
36 #include <asm/page.h>
37
38 #include <palacios/vm_guest_mem.h>
39 #include <interfaces/vmm_host_hypercall.h>
40
41
42 #include "devfile_hc.h"
43
44
45 #define DEEP_DEBUG    1
46 #define SHALLOW_DEBUG 1
47
48 #if DEEP_DEBUG
49 #define DEEP_DEBUG_PRINT(fmt, args...) printk(("devfile: " fmt), ##args)
50 #else
51 #define DEEP_DEBUG_PRINT(fmt, args...) 
52 #endif
53
54 #if SHALLOW_DEBUG
55 #define SHALLOW_DEBUG_PRINT(fmt, args...) printk(("devfile: " fmt), ##args)
56 #else
57 #define SHALLOW_DEBUG_PRINT(fmt, args...) 
58 #endif
59
60
61 #define ERROR(fmt, args...) printk(("devfile: " fmt), ##args)
62 #define INFO(fmt, args...) printk(("devfile: " fmt), ##args)
63
64 #define PRINT_CONSOLE(fmt,args...) printf(("devfile: " fmt),##args)
65
66
67
68
69 // Added to make unique id's for IOCTL
70 #define MY_MACIG 'G'
71 #define INIT_IOCTL _IOR(MY_MACIG, 0, int)
72 #define SHADOW_SYSCALL_DONE _IOW(MY_MACIG, 2, int)
73
74 #define DEVFILE_NAME "v3-devfile"
75
76 static int devfile_major_num = 0;
77 static struct class *devfile_class = 0;
78 static struct cdev devfile_dev;
79
80
81
82 struct devfile_state {
83     void     *shared_mem_va;
84     uint64_t  shared_mem_uva;
85     uint64_t  shared_mem_pa;
86     uint64_t returned_fd;
87
88     wait_queue_head_t user_wait_queue;
89     wait_queue_head_t host_wait_queue;
90
91     enum { WAIT_FOR_INIT, WAIT_ON_GUEST, WAIT_ON_SHADOW} state; 
92 } ;
93
94 // Currently this proof of concept supports a single userland/VM binding
95 // and is serially reusable
96 static struct devfile_state *state=0;
97
98 static inline struct devfile_state *find_matching_state(palacios_core_t core) { return state; } 
99
100
101 /* Hypercall helpers */ 
102
103 static void get_args_64(palacios_core_t core,
104                         struct guest_accessors *acc,
105                         uint64_t *a1,
106                         uint64_t *a2,
107                         uint64_t *a3,
108                         uint64_t *a4,
109                         uint64_t *a5,
110                         uint64_t *a6,
111                         uint64_t *a7,
112                         uint64_t *a8)
113 {
114     *a1 = acc->get_rcx(core);
115     *a2 = acc->get_rdx(core);
116     *a3 = acc->get_rsi(core);
117     *a4 = acc->get_rdi(core);
118     *a5 = acc->get_r8(core);
119     *a6 = acc->get_r9(core);
120     *a7 = acc->get_r10(core);
121     *a8 = acc->get_r11(core);
122 }
123
124 static void get_args_32(palacios_core_t core,
125                         struct guest_accessors *acc,
126                         uint64_t *a1,
127                         uint64_t *a2,
128                         uint64_t *a3,
129                         uint64_t *a4,
130                         uint64_t *a5,
131                         uint64_t *a6,
132                         uint64_t *a7,
133                         uint64_t *a8)
134 {
135     uint64_t rsp;
136     uint32_t temp;
137     
138     
139     rsp = acc->get_rsp(core);
140     
141     acc->read_gva(core,rsp,4,&temp); *a1=temp;
142     acc->read_gva(core,rsp+4,4,&temp); *a2=temp;
143     acc->read_gva(core,rsp+8,4,&temp); *a3=temp;
144     acc->read_gva(core,rsp+12,4,&temp); *a4=temp;
145     acc->read_gva(core,rsp+16,4,&temp); *a5=temp;
146     acc->read_gva(core,rsp+20,4,&temp); *a6=temp;
147     acc->read_gva(core,rsp+24,4,&temp); *a7=temp;
148     acc->read_gva(core,rsp+28,4,&temp); *a8=temp;
149 }
150
151 static void get_args(palacios_core_t core,
152                      struct guest_accessors *acc,
153                      uint64_t *a1,
154                      uint64_t *a2,
155                      uint64_t *a3,
156                      uint64_t *a4,
157                      uint64_t *a5,
158                      uint64_t *a6,
159                      uint64_t *a7,
160                      uint64_t *a8)
161 {
162     uint64_t rbx;
163     uint32_t ebx;
164     
165     rbx=acc->get_rbx(core);
166     ebx=rbx&0xffffffff;
167     
168     switch (ebx) {
169         case 0x64646464:
170             DEEP_DEBUG_PRINT("64 bit hcall\n");
171             return get_args_64(core,acc,a1,a2,a3,a4,a5,a6,a7,a8);
172             break;
173         case 0x32323232:
174             DEEP_DEBUG_PRINT("32 bit hcall\n");
175             return get_args_32(core,acc,a1,a2,a3,a4,a5,a6,a7,a8);
176             break;
177         default:
178             ERROR("UNKNOWN hcall calling convention\n");
179             break;
180     }
181 }
182
183 static void put_return(palacios_core_t core, 
184                        struct guest_accessors *acc,
185                        uint64_t rc,
186                        uint64_t errno)
187 {
188     acc->set_rax(core,rc);
189     acc->set_rbx(core,rc);
190 }
191         
192 /*
193   Convert all hypercall pointer arguments from GVAs to GPAs
194   The host userland is responsible for converting from 
195   GVAs to HVAs. 
196   
197   The assumption here is that any pointer argument
198   points to a structure that does NOT span a page
199   boundary.  The guest userland is responsible for
200   assuring that this is the case.
201 */           
202 static int deref_args(palacios_core_t core, 
203                       struct guest_accessors *acc,
204                       uint64_t* a1, uint64_t* a2, uint64_t* a3, uint64_t* a4, uint64_t* a5,
205                       uint64_t* a6, uint64_t bvec)
206 {
207     if (bvec & 1){
208         uint64_t a1tmp = *a1;
209         acc->gva_to_gpa(core,a1tmp,a1);
210     }
211     if (bvec & 2){
212         uint64_t a2tmp = *a2;
213         acc->gva_to_gpa(core,a2tmp,a2);
214     }
215     if (bvec & 4){
216         uint64_t a3tmp = *a3;
217         acc->gva_to_gpa(core,a3tmp,a3);
218     }
219     if (bvec & 8){
220         uint64_t a4tmp = *a4;
221         acc->gva_to_gpa(core,a4tmp,a4);
222     }
223     if (bvec & 16){
224         uint64_t a5tmp = *a5;
225         acc->gva_to_gpa(core,a5tmp,a5);
226     }
227     if (bvec & 32){
228         uint64_t a6tmp = *a6;
229         acc->gva_to_gpa(core,a6tmp,a6);
230     }
231     return 0; 
232 }
233
234
235 #if 0
236 /* Create /dev/v3-devfile in the host */
237
238 // User mode helper call to create module private chardev for ioctls
239 static int setup_mknod_call(int major_num)
240 {
241     //www.ibm.com/developerworks/library/l-user-space-apps/
242     struct subprocess_info *sub_info;  
243     char buf[20];
244     
245     snprintf(buf,20,"%d",major_num);
246     
247     const char *argv[] = { "/bin/mknod", "/dev/" DEVFILE_NAME,"c", buf, "0", NULL };
248     static char *envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/bin:/usr/sbin:/usr/bin", NULL };
249
250     sub_info = call_usermodehelper_setup( (char*)argv[0], (char**)argv, envp, GFP_ATOMIC );
251     
252     if (sub_info == NULL) {
253         ERROR("failed to create %s\n",DEVFILE_PATH);
254         return -ENOMEM;
255     }
256     
257     SHALLOW_DEBUG_PRINT("set up usermode call\n");
258     
259     return call_usermodehelper_exec( sub_info, UMH_WAIT_PROC );
260 }
261
262 #endif
263
264 static uint64_t devfile_syscall_return(struct devfile_state *s, uint64_t *errno)
265 {
266     uint64_t rc;
267     uint64_t *shared_page = (uint64_t*)(s->shared_mem_va);
268
269     s->state=WAIT_ON_SHADOW;
270
271     // kick the the user if needed
272     //!! IDEA: We can add Usermode Helper to start shadow process instead
273     // and wait for it to send us an ioctl to wake up the module. 
274     wake_up_interruptible(&(s->user_wait_queue));
275     // goto sleep until we see a message received
276     // part of a separate ioctl
277     SHALLOW_DEBUG_PRINT("waiting For Shadow Process\n");
278     while (wait_event_interruptible(s->host_wait_queue, (s->state==WAIT_ON_GUEST)) != 0) {}
279     SHALLOW_DEBUG_PRINT("waiting done\n");
280     // Get the returned value and errno
281     rc     = *(shared_page +8);
282     *errno = *(shared_page +9);
283
284     SHALLOW_DEBUG_PRINT("waiting done %016llu (errno %016llu)\n",rc,*errno);
285     return rc;
286 }
287
288
289 static int devfile_syscall_hcall(struct devfile_state *s, 
290                                  palacios_core_t core,
291                                  uint64_t sys_code,
292                                  uint64_t a1, uint64_t a2,uint64_t a3, 
293                                  uint64_t a4, uint64_t a5, uint64_t a6, 
294                                  uint64_t bit_vec, 
295                                  uint64_t *errno)
296 {
297     //Using shared memory page
298     uint64_t ret;
299     uint64_t *shared_page = (uint64_t*)(s->shared_mem_va);
300
301     *(shared_page +0) = sys_code;
302     *(shared_page +1) = a1;
303     *(shared_page +2) = a2;
304     *(shared_page +3) = a3;
305     *(shared_page +4) = a4;
306     *(shared_page +5) = a5;
307     *(shared_page +6) = a6;
308     *(shared_page +7) = bit_vec;
309
310     SHALLOW_DEBUG_PRINT("Host Module to wait on shadow\n");
311
312     //Now wait for rc and errno to be written to the shared page
313     ret = devfile_syscall_return(s, errno);
314
315     SHALLOW_DEBUG_PRINT("SYSCALL HCALL %016llu (errno %016llu)\n",ret,*errno);
316
317     return ret;
318 }
319
320
321
322 // The main Interface for Hypercalls
323 int devfile_hypercall(palacios_core_t *core,
324                       unsigned int hid,
325                       struct guest_accessors *acc,
326                       void *p)
327 {
328     uint64_t a1,a2,a3,a4,a5,a6,bit_vec,sys_code;
329     uint64_t rc;
330     uint64_t errno;
331     
332     struct devfile_state *s = find_matching_state(core);
333
334     if (s->state == WAIT_FOR_INIT){
335         SHALLOW_DEBUG_PRINT("Shared Memory Not Yet Initialized, returning syscall hypercall\n");
336         return -1;
337     }
338     
339     sys_code = 0;
340     bit_vec = 0;
341     
342     DEEP_DEBUG_PRINT("devfile_hypercall(%p,0x%x,%p,%p)\n",
343                      core,hid,acc,p);
344     
345     get_args(core,acc,&sys_code,&a1,&a2,&a3,&a4,&a5,&a6,&bit_vec);
346
347     DEEP_DEBUG_PRINT("original arguments: %016llu, %016llu, %016llu, %016llu, %016llu, %016llu, %016llu, %016llu\n",
348                      sys_code,a1,a2,a3,a4,a5,a6,bit_vec);
349     
350     // Convert any pointer arguments from GVAs to GPAs
351     deref_args(core,acc,&a1,&a2,&a3,&a4,&a5,&a6,bit_vec);
352
353     DEEP_DEBUG_PRINT("derefed arguments: %016llu, %016llu, %016llu, %016llu, %016llu, %016llu, %016llu, %016llu\n",
354                      sys_code,a1,a2,a3,a4,a5,a6,bit_vec);
355
356     rc = devfile_syscall_hcall(s,core,sys_code,a1,a2,a3,a4,a5,a6,bit_vec,&errno);
357
358     SHALLOW_DEBUG_PRINT("Syscall rc: %016llu errno=%016llu\n",rc,errno);
359
360     put_return(core,acc,rc,errno);
361
362     return 0;
363
364
365
366
367 static int devfile_open(struct inode * inode, struct file * filp) 
368 {
369     struct devfile_state *s = state;
370     
371     if (s) { 
372         ERROR("attempting to open devfile that is already open\n");
373         return -EINVAL;
374     }
375
376     s=(struct devfile_state*)kmalloc(sizeof(struct devfile_state),GFP_KERNEL);
377
378     if (!s) { 
379         ERROR("Failed to allocate space for open\n");
380         return -EINVAL;
381     }
382
383     // This hideousness is here because in this POC we
384     // are simply allowing a single userland to be tied to 
385     // a single VM.   At the same time, we are making 
386     // the rest of the code more flexible for the future
387     state = s;
388
389     memset(s,0,sizeof(*s));
390
391     init_waitqueue_head(&s->user_wait_queue);
392     init_waitqueue_head(&s->host_wait_queue);
393
394     s->state = WAIT_FOR_INIT;
395         
396     filp->private_data = (void*) s;
397
398     return 0;
399 }
400
401 static int devfile_close(struct inode * inode, struct file * filp) 
402 {
403     struct devfile_state *s = filp->private_data;
404     
405     if (s) { 
406         if (s->state==WAIT_ON_SHADOW) { 
407             ERROR("Odd, userland is closing devfile while we are waiting for it\n");
408         }
409         kfree(s);
410         state=0;
411     }
412     
413     return 0;
414
415 }
416
417
418 static long devfile_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) 
419 {
420     struct devfile_state *s = filp->private_data;
421
422     switch(cmd) {
423         case INIT_IOCTL:    
424             s->shared_mem_pa = (uint64_t)arg;
425             s->shared_mem_va = __va(s->shared_mem_pa);
426             SHALLOW_DEBUG_PRINT("Shared Memory Physical Address: %016llu\n",s->shared_mem_pa);
427             SHALLOW_DEBUG_PRINT("Shared Memory Kernel VA: %p\n",s->shared_mem_va);
428             //Change State to wait on guest
429             s->state = WAIT_ON_GUEST;
430             break;
431             
432         case SHADOW_SYSCALL_DONE:
433             s->state = WAIT_ON_GUEST;
434             wake_up_interruptible(&(s->host_wait_queue));
435             break;
436
437         default:
438             return -EINVAL;
439     }
440
441     return 0;
442
443 }
444
445
446 static unsigned int devfile_poll(struct file * filp, 
447                                  struct poll_table_struct * poll_tb) 
448 {
449     struct devfile_state *s = filp->private_data;
450
451     SHALLOW_DEBUG_PRINT("poll\n");
452
453     // register ourselves on the user wait queue
454     poll_wait(filp, &(s->user_wait_queue), poll_tb);
455
456     if (s->state==WAIT_ON_SHADOW) { 
457         // Yes, we have a request if you want it!
458         DEEP_DEBUG_PRINT("poll done immediate\n");
459         return  POLLIN | POLLRDNORM;
460     } 
461     // No request yet, so we need to wait for one to show up.
462     DEEP_DEBUG_PRINT("poll delayed\n");
463     // We will get called again when that queue is woken up
464
465     return 0;
466 }
467
468 static struct file_operations devfile_fops = {
469     .open     = devfile_open,
470     .release  = devfile_close,
471     .poll     = devfile_poll,
472     .unlocked_ioctl = devfile_ioctl,
473     .compat_ioctl = devfile_ioctl
474 };
475
476 EXPORT_SYMBOL(devfile_hypercall);
477
478 int init_module(void) 
479 {
480     dev_t dev;
481
482     SHALLOW_DEBUG_PRINT("INIT\n");
483   
484     devfile_class = class_create(THIS_MODULE,"devfile");
485     if (!devfile_class || IS_ERR(devfile_class)) { 
486         ERROR("Cannot register devfile device class\n");
487         return PTR_ERR(devfile_class);
488     }
489
490     dev = MKDEV(0,0);
491
492     if (alloc_chrdev_region(&dev,0,1,"devfile")<0) {
493         ERROR("Failed to alloc chrdev region\n");
494         return -1;
495     }
496
497     devfile_major_num = MAJOR(dev);
498
499     dev = MKDEV(devfile_major_num,1);
500
501     cdev_init(&devfile_dev, &devfile_fops);
502     devfile_dev.owner = THIS_MODULE;
503     devfile_dev.ops = &devfile_fops;
504     cdev_add(&devfile_dev, dev, 1);
505     
506     device_create(devfile_class, NULL, dev, NULL, "v3-devfile");
507
508 #if 0
509    // Setup chardev for IOCTL
510     major = register_chrdev(0,"dfvDev", &fops);
511     if(major < 0){
512         SHALLOW_DEBUG_PRINT("registering dfvDev char device failed with %d\n", major);
513         return major;
514     }
515     SHALLOW_DEBUG_PRINT("assigned major: %d\n", major);
516     SHALLOW_DEBUG_PRINT("creating node with mknod %s c %d 0\n", DEVFILE_PATH, major);
517
518     // Call Helper API function to setup chardev
519     rc = setup_mknod_call(major);
520     SHALLOW_DEBUG_PRINT("UMH api mknod %s c %d 0 -- ret: %d\n\n", DEVFILE_PATH, major,rc);
521
522 #endif
523
524     INFO("inited\n");
525     
526     return 0;
527 }
528
529 void cleanup_module(void) 
530 {
531     dev_t dev = MKDEV(devfile_major_num,1);
532
533     unregister_chrdev_region(MKDEV(devfile_major_num,0),1);
534     cdev_del(&devfile_dev);
535     device_destroy(devfile_class,dev);
536     class_destroy(devfile_class);
537
538 #if 0
539     unregister_chrdev(major, "dfvDev");
540 #endif
541     if (state) {
542         kfree(state);
543     }
544
545     INFO("deinited\n");
546 }