2 Device File Virtualization Host Module
4 (c) Akhil Guliani and William Gross, 2015
6 Adapted from MPI module (c) 2012 Peter Dinda
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>
17 #include <linux/kernel.h>
18 #include <linux/slab.h>
20 #include <linux/sched.h>
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>
29 #include <linux/file.h>
30 #include <linux/fcntl.h>
31 #include <linux/device.h>
32 #include <linux/cdev.h>
34 #include <asm/uaccess.h>
38 #include <palacios/vm_guest_mem.h>
39 #include <interfaces/vmm_host_hypercall.h>
42 #include "devfile_hc.h"
46 #define SHALLOW_DEBUG 1
49 #define DEEP_DEBUG_PRINT(fmt, args...) printk(("devfile: " fmt), ##args)
51 #define DEEP_DEBUG_PRINT(fmt, args...)
55 #define SHALLOW_DEBUG_PRINT(fmt, args...) printk(("devfile: " fmt), ##args)
57 #define SHALLOW_DEBUG_PRINT(fmt, args...)
61 #define ERROR(fmt, args...) printk(("devfile: " fmt), ##args)
62 #define INFO(fmt, args...) printk(("devfile: " fmt), ##args)
64 #define PRINT_CONSOLE(fmt,args...) printf(("devfile: " fmt),##args)
69 // Added to make unique id's for IOCTL
71 #define INIT_IOCTL _IOR(MY_MACIG, 0, int)
72 #define SHADOW_SYSCALL_DONE _IOW(MY_MACIG, 2, int)
74 #define DEVFILE_NAME "v3-devfile"
76 static int devfile_major_num = 0;
77 static struct class *devfile_class = 0;
78 static struct cdev devfile_dev;
82 struct devfile_state {
84 uint64_t shared_mem_uva;
85 uint64_t shared_mem_pa;
88 wait_queue_head_t user_wait_queue;
89 wait_queue_head_t host_wait_queue;
91 enum { WAIT_FOR_INIT, WAIT_ON_GUEST, WAIT_ON_SHADOW} state;
94 // Currently this proof of concept supports a single userland/VM binding
95 // and is serially reusable
96 static struct devfile_state *state=0;
98 static inline struct devfile_state *find_matching_state(palacios_core_t core) { return state; }
101 /* Hypercall helpers */
103 static void get_args_64(palacios_core_t core,
104 struct guest_accessors *acc,
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);
124 static void get_args_32(palacios_core_t core,
125 struct guest_accessors *acc,
139 rsp = acc->get_rsp(core);
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;
151 static void get_args(palacios_core_t core,
152 struct guest_accessors *acc,
165 rbx=acc->get_rbx(core);
170 DEEP_DEBUG_PRINT("64 bit hcall\n");
171 return get_args_64(core,acc,a1,a2,a3,a4,a5,a6,a7,a8);
174 DEEP_DEBUG_PRINT("32 bit hcall\n");
175 return get_args_32(core,acc,a1,a2,a3,a4,a5,a6,a7,a8);
178 ERROR("UNKNOWN hcall calling convention\n");
183 static void put_return(palacios_core_t core,
184 struct guest_accessors *acc,
188 acc->set_rax(core,rc);
189 acc->set_rbx(core,errno);
193 Convert all hypercall pointer arguments from GVAs to GPAs
194 The host userland is responsible for converting from
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.
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)
208 uint64_t a1tmp = *a1;
209 acc->gva_to_gpa(core,a1tmp,a1);
212 uint64_t a2tmp = *a2;
213 acc->gva_to_gpa(core,a2tmp,a2);
216 uint64_t a3tmp = *a3;
217 acc->gva_to_gpa(core,a3tmp,a3);
220 uint64_t a4tmp = *a4;
221 acc->gva_to_gpa(core,a4tmp,a4);
224 uint64_t a5tmp = *a5;
225 acc->gva_to_gpa(core,a5tmp,a5);
228 uint64_t a6tmp = *a6;
229 acc->gva_to_gpa(core,a6tmp,a6);
236 static uint64_t devfile_syscall_return(struct devfile_state *s, uint64_t *errno)
239 uint64_t *shared_page = (uint64_t*)(s->shared_mem_va);
241 s->state=WAIT_ON_SHADOW;
243 // kick the the user if needed
244 //!! IDEA: We can add Usermode Helper to start shadow process instead
245 // and wait for it to send us an ioctl to wake up the module.
246 wake_up_interruptible(&(s->user_wait_queue));
247 // goto sleep until we see a message received
248 // part of a separate ioctl
249 SHALLOW_DEBUG_PRINT("waiting For Shadow Process\n");
250 while (wait_event_interruptible(s->host_wait_queue, (s->state==WAIT_ON_GUEST)) != 0) {}
251 SHALLOW_DEBUG_PRINT("waiting done\n");
252 // Get the returned value and errno
253 rc = *(shared_page +8);
254 *errno = *(shared_page +9);
256 SHALLOW_DEBUG_PRINT("waiting done %016llu (errno %016llu)\n",rc,*errno);
261 static int devfile_syscall_hcall(struct devfile_state *s,
262 palacios_core_t core,
264 uint64_t a1, uint64_t a2,uint64_t a3,
265 uint64_t a4, uint64_t a5, uint64_t a6,
269 //Using shared memory page
271 uint64_t *shared_page = (uint64_t*)(s->shared_mem_va);
273 *(shared_page +0) = sys_code;
274 *(shared_page +1) = a1;
275 *(shared_page +2) = a2;
276 *(shared_page +3) = a3;
277 *(shared_page +4) = a4;
278 *(shared_page +5) = a5;
279 *(shared_page +6) = a6;
280 *(shared_page +7) = bit_vec;
282 SHALLOW_DEBUG_PRINT("Host Module to wait on shadow\n");
284 //Now wait for rc and errno to be written to the shared page
285 ret = devfile_syscall_return(s, errno);
287 SHALLOW_DEBUG_PRINT("SYSCALL HCALL %016llu (errno %016llu)\n",ret,*errno);
294 // The main Interface for Hypercalls
295 int devfile_hypercall(palacios_core_t *core,
297 struct guest_accessors *acc,
300 uint64_t a1,a2,a3,a4,a5,a6,bit_vec,sys_code;
304 struct devfile_state *s = find_matching_state(core);
306 if (s->state == WAIT_FOR_INIT){
307 SHALLOW_DEBUG_PRINT("Shared Memory Not Yet Initialized, returning syscall hypercall\n");
314 DEEP_DEBUG_PRINT("devfile_hypercall(%p,0x%x,%p,%p)\n",
317 get_args(core,acc,&sys_code,&a1,&a2,&a3,&a4,&a5,&a6,&bit_vec);
319 DEEP_DEBUG_PRINT("original arguments: %016llu, %016llu, %016llu, %016llu, %016llu, %016llu, %016llu, %016llu\n",
320 sys_code,a1,a2,a3,a4,a5,a6,bit_vec);
322 // Convert any pointer arguments from GVAs to GPAs
323 deref_args(core,acc,&a1,&a2,&a3,&a4,&a5,&a6,bit_vec);
325 DEEP_DEBUG_PRINT("derefed arguments: %016llu, %016llu, %016llu, %016llu, %016llu, %016llu, %016llu, %016llu\n",
326 sys_code,a1,a2,a3,a4,a5,a6,bit_vec);
328 rc = devfile_syscall_hcall(s,core,sys_code,a1,a2,a3,a4,a5,a6,bit_vec,&errno);
330 SHALLOW_DEBUG_PRINT("Syscall rc: %016llu errno=%016llu\n",rc,errno);
332 put_return(core,acc,rc,errno);
339 static int devfile_open(struct inode * inode, struct file * filp)
341 struct devfile_state *s = state;
344 ERROR("attempting to open devfile that is already open\n");
348 s=(struct devfile_state*)kmalloc(sizeof(struct devfile_state),GFP_KERNEL);
351 ERROR("Failed to allocate space for open\n");
355 // This hideousness is here because in this POC we
356 // are simply allowing a single userland to be tied to
357 // a single VM. At the same time, we are making
358 // the rest of the code more flexible for the future
361 memset(s,0,sizeof(*s));
363 init_waitqueue_head(&s->user_wait_queue);
364 init_waitqueue_head(&s->host_wait_queue);
366 s->state = WAIT_FOR_INIT;
368 filp->private_data = (void*) s;
373 static int devfile_close(struct inode * inode, struct file * filp)
375 struct devfile_state *s = filp->private_data;
378 if (s->state==WAIT_ON_SHADOW) {
379 ERROR("Odd, userland is closing devfile while we are waiting for it\n");
390 static long devfile_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
392 struct devfile_state *s = filp->private_data;
396 s->shared_mem_pa = (uint64_t)arg;
397 s->shared_mem_va = __va(s->shared_mem_pa);
398 SHALLOW_DEBUG_PRINT("Shared Memory Physical Address: %016llu\n",s->shared_mem_pa);
399 SHALLOW_DEBUG_PRINT("Shared Memory Kernel VA: %p\n",s->shared_mem_va);
400 //Change State to wait on guest
401 s->state = WAIT_ON_GUEST;
404 case SHADOW_SYSCALL_DONE:
405 s->state = WAIT_ON_GUEST;
406 wake_up_interruptible(&(s->host_wait_queue));
418 static unsigned int devfile_poll(struct file * filp,
419 struct poll_table_struct * poll_tb)
421 struct devfile_state *s = filp->private_data;
423 SHALLOW_DEBUG_PRINT("poll\n");
425 // register ourselves on the user wait queue
426 poll_wait(filp, &(s->user_wait_queue), poll_tb);
428 if (s->state==WAIT_ON_SHADOW) {
429 // Yes, we have a request if you want it!
430 DEEP_DEBUG_PRINT("poll done immediate\n");
431 return POLLIN | POLLRDNORM;
433 // No request yet, so we need to wait for one to show up.
434 DEEP_DEBUG_PRINT("poll delayed\n");
435 // We will get called again when that queue is woken up
440 static struct file_operations devfile_fops = {
441 .open = devfile_open,
442 .release = devfile_close,
443 .poll = devfile_poll,
444 .unlocked_ioctl = devfile_ioctl,
445 .compat_ioctl = devfile_ioctl
448 EXPORT_SYMBOL(devfile_hypercall);
450 int init_module(void)
454 SHALLOW_DEBUG_PRINT("INIT\n");
456 devfile_class = class_create(THIS_MODULE,"devfile");
457 if (!devfile_class || IS_ERR(devfile_class)) {
458 ERROR("Cannot register devfile device class\n");
459 return PTR_ERR(devfile_class);
464 if (alloc_chrdev_region(&dev,0,1,"devfile")<0) {
465 ERROR("Failed to alloc chrdev region\n");
469 devfile_major_num = MAJOR(dev);
471 dev = MKDEV(devfile_major_num,1);
473 cdev_init(&devfile_dev, &devfile_fops);
474 devfile_dev.owner = THIS_MODULE;
475 devfile_dev.ops = &devfile_fops;
476 cdev_add(&devfile_dev, dev, 1);
478 device_create(devfile_class, NULL, dev, NULL, "v3-devfile");
486 void cleanup_module(void)
488 dev_t dev = MKDEV(devfile_major_num,1);
490 unregister_chrdev_region(MKDEV(devfile_major_num,0),1);
491 cdev_del(&devfile_dev);
492 device_destroy(devfile_class,dev);
493 class_destroy(devfile_class);
503 MODULE_LICENSE("GPL");