2 * Device File Virtualization Userland Shadow
3 * (c) Akhil Guliani and William Gross, 2015
11 #include <sys/ioctl.h>
13 #include <sys/types.h>
22 #include <sys/socket.h>
24 #include <linux/wait.h>
25 #include <sys/select.h>
27 #include "v3_guest_mem.h"
29 #define DEV_FILE_IOCTL_PATH "/dev/v3-devfile"
31 // IOCTL codes for signalling
33 #define INIT_IOCTL _IOR(MY_MACIG, 0, int)
34 #define WRITE_IOCTL _IOW(MY_MACIG, 1, int)
35 #define SHADOW_SYSCALL_DONE _IOW(MY_MACIG, 2, int)
39 #define DEBUG_PRINT(fmt, args...) printf(fmt, ##args)
41 #define DEBUG_PRINT(fmt, args...)
45 //Helper function to generate user virtual address for a given guest physical address
46 static inline uint64_t get_uva_from_gpa(struct v3_guest_mem_map *map, uint64_t gpa)
49 uint64_t prev_gpa, prev_uva, offset;
52 for (i=0; i< map->numblocks; i++) {
53 if(gpa < (uint64_t)map->block[i].gpa){
54 offset = gpa - prev_gpa;
55 DEBUG_PRINT("gpa %lx, prev_gpa %lx, offset %lx, res %lx\n",gpa,prev_gpa,offset,prev_uva+offset);
56 return prev_uva+offset;
58 prev_uva = (uint64_t)map->block[i].uva;
63 prev_gpa = (uint64_t)map->block[i].gpa;
68 static inline int deref_args(struct v3_guest_mem_map *map,
69 uint64_t * a1, uint64_t * a2,
70 uint64_t * a3, uint64_t * a4,
71 uint64_t * a5, uint64_t * a6,
75 DEBUG_PRINT("bvec 1\n");
77 *a1 = get_uva_from_gpa(map,a1tmp);
80 DEBUG_PRINT("bvec 2\n");
82 *a2 = get_uva_from_gpa(map,a2tmp);
85 DEBUG_PRINT("bvec 4\n");
87 *a3 = get_uva_from_gpa(map,a3tmp);
90 DEBUG_PRINT("bvec 8\n");
92 *a4 = get_uva_from_gpa(map,a4tmp);
95 DEBUG_PRINT("bvec 16\n");
97 *a5 = get_uva_from_gpa(map,a5tmp);
100 DEBUG_PRINT("bvec 32\n");
101 uint64_t a6tmp = *a6;
102 *a6 = get_uva_from_gpa(map,a6tmp);
107 static inline int store_args_to_shared_page(uint64_t* shared_page, uint64_t* return_val, uint64_t *sys_errno)
109 *(shared_page+8) = *return_val;
110 *(shared_page+9) = *sys_errno;
114 static inline int load_args_from_shared_page(uint64_t* shared_page,
116 uint64_t* a1, uint64_t* a2, uint64_t* a3,
117 uint64_t* a4, uint64_t* a5, uint64_t* a6,
120 *sys_code = *shared_page;
121 *a1 = *(shared_page+1);
122 *a2 = *(shared_page+2);
123 *a3 = *(shared_page+3);
124 *a4 = *(shared_page+4);
125 *a5 = *(shared_page+5);
126 *a6 = *(shared_page+6);
127 *bit_vec = *(shared_page+7);
133 // Get Physical address for given virtual address
135 // This is horrific, but note that it is used only to locate
136 // the shared page - it is not used in the main execution loop
137 static uint64_t vtop(uint64_t vaddr)
141 uint64_t offset = (vaddr / sysconf(_SC_PAGESIZE)) * sizeof(uint64_t);
144 sprintf(addr,"/proc/%d/pagemap", getpid());
145 DEBUG_PRINT("Page size : %ld, Offset: %lu, In vtop",sysconf(_SC_PAGESIZE),offset);
146 // https://www.kernel.org/doc/Documentation/vm/pagemap.txt
147 if ((pagemap = fopen(addr, "r"))) {
148 if (lseek(fileno(pagemap), offset, SEEK_SET) == offset) {
149 if (fread(&e, sizeof(uint64_t), 1, pagemap)) {
150 if (e & (1ULL << 63)) { // page present ?
151 paddr = e & ((1ULL << 54) - 1); // pfn mask
152 paddr = paddr * sysconf(_SC_PAGESIZE);
153 // add offset within page
154 paddr = paddr | (vaddr & (sysconf(_SC_PAGESIZE) - 1));
161 DEBUG_PRINT("The returned conversion is vaddr %p to paddr %p \n",(void*)vaddr,(void*)paddr);
170 printf("v3_devfile_shadow <vm_device>\n\n");
171 printf("Shadow process to support device file-level virtualization\n"
172 "in the spirit of Paradice.\n\n"
173 "This operates with the devfile_host.ko kernel module\n"
174 "in the host and devfile_preload.so preload library in\n"
175 "the guest. These can be found, along with example scripts\n"
176 "in palacios/gears/services/devfile.\n\n"
177 "The general steps are:\n"
178 " 1. insmod kernel module into host\n"
179 " 2. copy preload library into guest\n"
180 " 3. instantiate guest\n"
181 " 4. use v3_hypercall to bind the devfile hypercall (99993)\n"
182 " to the kernel module for your guest\n"
183 " 5. run v3_devfile_shadow\n"
184 " 6. run process in guest that uses preload library\n\n");
187 int main(int argc, char** argv)
190 struct v3_guest_mem_map *map;
191 uint64_t sys_rc, sys_errno, sys_code, a1,a2,a3,a4,a5,a6, bit_vec;
192 int host_mod_fd, fd_shared, i, val;
194 void* unbacked_region;
205 if (!(map=v3_guest_mem_get_map(argv[1]))) {
206 DEBUG_PRINT("Cannot get guest memory map for %s\n",argv[1]);
210 if (v3_map_guest_mem(map)) {
211 DEBUG_PRINT("Cannot map guest memory\n");
216 for (i=0; i< map->numblocks; i++) {
217 DEBUG_PRINT("Region %d: gpa=%p, hpa=%p, uva=%p, numpages=%lu\n",
218 i, map->block[i].gpa, map->block[i].hpa,map->block[i].uva, map->block[i].numpages);
223 if ((host_mod_fd = open(DEV_FILE_IOCTL_PATH, O_RDWR)) < 0) {
228 unbacked_region = mmap(NULL,4096,PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED | MAP_ANONYMOUS, -1,0);
230 if (unbacked_region == MAP_FAILED){
231 perror("Anon Region: ");
235 sprintf(unbacked_region,"helloworldhelloworldhelloworld");
237 DEBUG_PRINT("unbacked_region ptr: %p contents: %s\n",unbacked_region,(char*)unbacked_region);
238 DEBUG_PRINT("Vaddr : %p ; Paddr : %p\n", (void*)unbacked_region, (void*)vtop((uint64_t)unbacked_region));
239 DEBUG_PRINT("Persisting as a userspace for VM %s with address %p\n",argv[1], unbacked_region);
241 if (ioctl(host_mod_fd,INIT_IOCTL,vtop((uint64_t)unbacked_region))) {
242 perror("init ioctl");
248 FD_SET(host_mod_fd,&readset);
250 select_rc = select(host_mod_fd+1,&readset,0,0,0);
256 perror("Select failed");
261 DEBUG_PRINT("Device File: Handling a forwarded system call\n");
263 //Get syscall arguments from shared page
264 load_args_from_shared_page((uint64_t*)unbacked_region,&sys_code,&a1,&a2,&a3,&a4,&a5,&a6,&bit_vec);
266 //Extract Guest pointer arguments and map them to current userspace
267 DEBUG_PRINT("About to deref args\nsys_code: %016lu, a1: %016lu, a2: %016lu,\na3: %016lu,a4: %016lu,a5: %016lu,a6: %016lu,bit_vec: %016lu\n", sys_code, a1, a2, a3,a4,a5,a6,bit_vec);
269 // swizzle pointers from their GPAs to their HVAs
270 deref_args(map,&a1,&a2,&a3,&a4,&a5,&a6,bit_vec);
272 DEBUG_PRINT("Derefed args\nsys_code: %016lu, a1: %016lu, a2: %016lu,\na3: %016lu,a4: %016lu,a5: %016lu,a6: %016lu,bit_vec: %016lu\n", sys_code, a1, a2, a3,a4,a5,a6,bit_vec);
274 sys_rc = syscall(sys_code,a1,a2,a3,a4,a5,a6);
278 perror("Failed Syscall: ");
281 DEBUG_PRINT("Device File: System call rc %d, errno %lu\n",(int)sys_rc,sys_errno);
283 //put return value into shared region
284 store_args_to_shared_page((uint64_t*)unbacked_region, &sys_rc, &sys_errno);
286 // return to host module
287 ioctl(host_mod_fd,SHADOW_SYSCALL_DONE,0);