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.


Cleanup based on cppcheck pass (Linux module and user)
[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* unbacked_region;
195      fd_set readset;
196      int select_rc;
197
198
199
200      if (argc!=2) {
201          usage();
202          return 0;
203      }
204
205      if (!(map=v3_guest_mem_get_map(argv[1]))) { 
206          DEBUG_PRINT("Cannot get guest memory map for %s\n",argv[1]);
207          return -1;
208      }
209
210      if (v3_map_guest_mem(map)) { 
211          DEBUG_PRINT("Cannot map guest memory\n");
212          free(map);
213          return -1;
214      }
215
216      for (i=0; i< map->numblocks; i++) { 
217          DEBUG_PRINT("Region %llu: gpa=%p, hpa=%p, uva=%p, numpages=%llu\n", 
218                  i, map->block[i].gpa, map->block[i].hpa,map->block[i].uva, map->block[i].numpages);
219
220      }  
221
222
223      if ((host_mod_fd = open(DEV_FILE_IOCTL_PATH, O_RDWR)) < 0) {
224          perror("open");
225          return -1;
226      }
227
228      unbacked_region = mmap(NULL,4096,PROT_READ | PROT_WRITE, MAP_SHARED | MAP_LOCKED | MAP_ANONYMOUS, -1,0);
229
230      if (unbacked_region == MAP_FAILED){
231          perror("Anon Region: ");
232          return -1;
233      }
234
235      sprintf(unbacked_region,"helloworldhelloworldhelloworld");
236
237      DEBUG_PRINT("unbacked_region ptr: %p contents: %s\n",unbacked_region,(char*)unbacked_region);
238      DEBUG_PRINT("Vaddr : %p ; Paddr : %p\n", unbacked_region, vtop((uint64_t)unbacked_region));
239      DEBUG_PRINT("Persisting as a userspace for VM %s with address %p\n",argv[1], unbacked_region);
240
241      if (ioctl(host_mod_fd,INIT_IOCTL,vtop((uint64_t)unbacked_region))) {
242          perror("init ioctl");
243          return -1;
244      }
245
246      while (1) { 
247          FD_ZERO(&readset);
248          FD_SET(host_mod_fd,&readset);
249
250          select_rc = select(host_mod_fd+1,&readset,0,0,0);
251
252          if (select_rc<0) { 
253              if (errno==EAGAIN) { 
254                  continue;
255              } else {
256                  perror("Select failed");
257                  return -1;
258              }
259          }
260
261          DEBUG_PRINT("Device File: Handling a forwarded system call\n");
262
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);
265
266          //Extract Guest pointer arguments and map them to current userspace
267          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);
268
269          // swizzle pointers from their GPAs to their HVAs
270          deref_args(map,&a1,&a2,&a3,&a4,&a5,&a6,bit_vec);
271
272          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);
273
274          sys_rc = syscall(sys_code,a1,a2,a3,a4,a5,a6);            
275          sys_errno = errno;
276
277          if (sys_rc < 0){
278              perror("Failed Syscall: ");
279          }
280
281          DEBUG_PRINT("Device File: System call rc %d, errno %d\n",(int)sys_rc,sys_errno);
282
283          //put return value into shared region
284          store_args_to_shared_page((uint64_t*)unbacked_region, &sys_rc, &sys_errno); 
285
286          // return to host module
287          ioctl(host_mod_fd,SHADOW_SYSCALL_DONE,0);
288
289      }
290
291      return 0;
292
293  }