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.


dc4cddc952c99a4f801824f42a8e94dd0538b6de
[palacios.git] / linux_usr / v3_devfile_shadow.c
1 /* 
2  * Device File Virtualization Userland Shadow 
3  * (c) Akhil Guliani and William Gross, 2015
4  */
5
6
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <fcntl.h> 
11 #include <sys/ioctl.h> 
12 #include <sys/stat.h> 
13 #include <sys/types.h> 
14 #include <unistd.h> 
15 #include <string.h>
16 #include <getopt.h> 
17 #include <errno.h>
18
19 //DEV File include
20 #include <sys/mman.h>
21 #include <stdint.h>
22 #include <sys/socket.h>
23 #include <signal.h>
24 #include <linux/wait.h>
25 #include <sys/select.h>
26
27 #include "v3_guest_mem.h"
28
29 #define DEV_FILE_IOCTL_PATH "/dev/v3-devfile"
30
31 // IOCTL codes for signalling
32 #define MY_MACIG 'G'
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)
36
37
38 #if 1
39 #define DEBUG_PRINT(fmt, args...) printf(fmt, ##args)
40 #else
41 #define DEBUG_PRINT(fmt, args...) 
42 #endif
43
44
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)
47 {
48     int i;
49     uint64_t prev_gpa, prev_uva, offset;
50     prev_gpa = 0;
51     prev_uva = 0;
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 %llx, prev_gpa %llx, offset %llx, res %llx\n",gpa,prev_gpa,offset,prev_uva+offset);
56             return prev_uva+offset;
57         }
58         prev_uva = (uint64_t)map->block[i].uva;
59         if(i==0){
60             prev_gpa = 0;
61         }
62         else{
63             prev_gpa = (uint64_t)map->block[i].gpa;
64         }
65     } 
66 }
67
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, 
72                              uint64_t bvec)
73 {
74     if (bvec & 1){
75         DEBUG_PRINT("bvec 1\n");
76         uint64_t a1tmp = *a1;
77         *a1 = get_uva_from_gpa(map,a1tmp);
78     }
79     if (bvec & 2){
80         DEBUG_PRINT("bvec 2\n");
81         uint64_t a2tmp = *a2;
82         *a2 = get_uva_from_gpa(map,a2tmp);
83     }
84     if (bvec & 4){
85         DEBUG_PRINT("bvec 4\n");
86         uint64_t a3tmp = *a3;
87         *a3 = get_uva_from_gpa(map,a3tmp);
88     }
89     if (bvec & 8){
90         DEBUG_PRINT("bvec 8\n");
91         uint64_t a4tmp = *a4;
92         *a4 = get_uva_from_gpa(map,a4tmp);
93     }
94     if (bvec & 16){
95         DEBUG_PRINT("bvec 16\n");
96         uint64_t a5tmp = *a5;
97         *a5 = get_uva_from_gpa(map,a5tmp);
98     }
99     if (bvec & 32){
100         DEBUG_PRINT("bvec 32\n");
101         uint64_t a6tmp = *a6;
102         *a6 = get_uva_from_gpa(map,a6tmp);
103     }
104     return 0; 
105 }
106
107 static inline int store_args_to_shared_page(uint64_t* shared_page, uint64_t* return_val, uint64_t *sys_errno)
108 {
109     *(shared_page+8) = *return_val;
110     *(shared_page+9) = *sys_errno;
111     return 0;
112 }
113     
114 static inline int load_args_from_shared_page(uint64_t* shared_page,
115                                              uint64_t* sys_code,
116                                              uint64_t* a1, uint64_t* a2, uint64_t* a3,
117                                              uint64_t* a4, uint64_t* a5, uint64_t* a6,
118                                              uint64_t* bit_vec)
119 {
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);
128     return 0;
129 };
130
131
132
133 // Get Physical address for given virtual address 
134 //
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) 
138 {
139     FILE *pagemap;
140     uint64_t paddr = 0;
141     uint64_t offset = (vaddr / sysconf(_SC_PAGESIZE)) * sizeof(uint64_t);
142     uint64_t e;
143     char addr[80];
144     sprintf(addr,"/proc/%d/pagemap", getpid());
145     DEBUG_PRINT("Page size : %d, Offset: %d, 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));
155                 }   
156             }   
157         }   
158         fclose(pagemap);
159     }   
160
161     DEBUG_PRINT("The returned conversion is vaddr %p to paddr %p \n",(void*)vaddr,(void*)paddr);
162     return paddr;
163 }
164
165
166
167
168 void usage()
169 {
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");
185 }
186
187 int main(int argc, char** argv)
188 {
189
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;
193      long long zero = 0;
194      void* region;
195      void* unbacked_region;
196      fd_set readset;
197      int select_rc;
198
199
200
201      if (argc!=2) {
202          usage();
203          return 0;
204      }
205
206      if (!(map=v3_guest_mem_get_map(argv[1]))) { 
207          DEBUG_PRINT("Cannot get guest memory map for %s\n",argv[1]);
208          return -1;
209      }
210
211      if (v3_map_guest_mem(map)) { 
212          DEBUG_PRINT("Cannot map guest memory\n");
213          free(map);
214          return -1;
215      }
216
217      for (i=0; i< map->numblocks; i++) { 
218          DEBUG_PRINT("Region %llu: gpa=%p, hpa=%p, uva=%p, numpages=%llu\n", 
219                  i, map->block[i].gpa, map->block[i].hpa,map->block[i].uva, map->block[i].numpages);
220
221      }  
222
223
224      if ((host_mod_fd = open(DEV_FILE_IOCTL_PATH, O_RDWR)) < 0) {
225          perror("open");
226          return -1;
227      }
228
229      unbacked_region = mmap(NULL,4096,PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED | MAP_ANONYMOUS, -1,0);
230
231      if (unbacked_region == MAP_FAILED){
232          perror("Anon Region: ");
233          return -1;
234      }
235
236      sprintf(unbacked_region,"helloworldhelloworldhelloworld");
237
238      DEBUG_PRINT("unbacked_region ptr: %p contents: %s\n",unbacked_region,(char*)unbacked_region);
239      DEBUG_PRINT("Vadrr : %p ; Paddr : %p\n", unbacked_region, vtop((uint64_t)unbacked_region));
240      DEBUG_PRINT("Persisting as a userspace for VM %s with address %p\n",argv[1], region);
241
242      if (ioctl(host_mod_fd,INIT_IOCTL,vtop((uint64_t)unbacked_region))) {
243          perror("init ioctl");
244          return -1;
245      }
246
247      while (1) { 
248          FD_ZERO(&readset);
249          FD_SET(host_mod_fd,&readset);
250
251          select_rc = select(host_mod_fd+1,&readset,0,0,0);
252
253          if (select_rc<0) { 
254              if (errno==EAGAIN) { 
255                  continue;
256              } else {
257                  perror("Select failed");
258                  return -1;
259              }
260          }
261
262          DEBUG_PRINT("Device File: Handling a forwarded system call\n");
263
264          //Get syscall arguments from shared page
265          load_args_from_shared_page((uint64_t*)unbacked_region,&sys_code,&a1,&a2,&a3,&a4,&a5,&a6,&bit_vec);
266
267          //Extract Guest pointer arguments and map them to current userspace
268          DEBUG_PRINT("About to deref args\nsys_code: %016llu, a1: %016llu, a2: %016llu,\na3: %016llu,a4: %016llu,a5: %016llu,a6: %016llu,bit_vec: %016llu\n", sys_code, a1, a2, a3,a4,a5,a6,bit_vec);
269
270          // swizzle pointers from their GPAs to their HVAs
271          deref_args(map,&a1,&a2,&a3,&a4,&a5,&a6,bit_vec);
272
273          DEBUG_PRINT("Derefed args\nsys_code: %016llu, a1: %016llu, a2: %016llu,\na3: %016llu,a4: %016llu,a5: %016llu,a6: %016llu,bit_vec: %016llu\n", sys_code, a1, a2, a3,a4,a5,a6,bit_vec);
274
275          sys_rc = syscall(sys_code,a1,a2,a3,a4,a5,a6);            
276          sys_errno = errno;
277
278          if (sys_rc < 0){
279              perror("Failed Syscall: ");
280          }
281
282          DEBUG_PRINT("Device File: System call rc %d, %016llu %016llx %016lld\n",(int)sys_rc,sys_rc);
283
284          //put return value into shared region
285          store_args_to_shared_page((uint64_t*)unbacked_region, &sys_rc, &sys_errno); 
286
287          // return to host module
288          ioctl(host_mod_fd,SHADOW_SYSCALL_DONE,0);
289
290      }
291
292      return 0;
293
294  }