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.


added emulator
[palacios.git] / palacios / src / palacios / vmm_mem.c
1 #include <palacios/vmm_mem.h>
2 #include <palacios/vmm.h>
3 #include <palacios/vmm_util.h>
4 #include <palacios/vmm_decoder.h>
5
6
7
8 void init_shadow_region(struct shadow_region * entry,
9                         addr_t               guest_addr_start,
10                         addr_t               guest_addr_end,
11                         guest_region_type_t  guest_region_type,
12                         host_region_type_t   host_region_type)
13 {
14   entry->guest_type = guest_region_type;
15   entry->guest_start = guest_addr_start;
16   entry->guest_end = guest_addr_end;
17   entry->host_type = host_region_type;
18   entry->host_addr = 0;
19   entry->next=entry->prev = NULL;
20 }
21
22 int add_shadow_region_passthrough( struct guest_info *  guest_info,
23                                    addr_t               guest_addr_start,
24                                    addr_t               guest_addr_end,
25                                    addr_t               host_addr)
26 {
27   struct shadow_region * entry = (struct shadow_region *)V3_Malloc(sizeof(struct shadow_region));
28
29   init_shadow_region(entry, guest_addr_start, guest_addr_end, 
30                      GUEST_REGION_PHYSICAL_MEMORY, HOST_REGION_PHYSICAL_MEMORY);
31   entry->host_addr = host_addr;
32
33   return add_shadow_region(&(guest_info->mem_map), entry);
34 }
35
36 int hook_guest_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end,
37                    int (*read)(addr_t guest_addr, void * dst, uint_t length, void * priv_data),
38                    int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
39                    void * priv_data) {
40   
41   struct shadow_region * entry = (struct shadow_region *)V3_Malloc(sizeof(struct shadow_region));
42   struct vmm_mem_hook * hook = (struct vmm_mem_hook *)V3_Malloc(sizeof(struct vmm_mem_hook));
43
44   memset(hook, 0, sizeof(struct vmm_mem_hook));
45
46   hook->read = read;
47   hook->write = write;
48   hook->region = entry;
49   hook->priv_data = priv_data;
50
51
52   init_shadow_region(entry, guest_addr_start, guest_addr_end, 
53                      GUEST_REGION_PHYSICAL_MEMORY, HOST_REGION_HOOK);
54
55   entry->host_addr = (addr_t)hook;
56
57   return add_shadow_region(&(info->mem_map), entry);
58 }
59
60
61 struct vmm_mem_hook * get_mem_hook(struct guest_info * info, addr_t guest_addr) {
62   struct shadow_region * region = get_shadow_region_by_addr(&(info->mem_map), guest_addr);
63
64   if (region == NULL) {
65     PrintDebug("Could not find shadow region for addr: %x\n", guest_addr);
66     return NULL;
67   }
68
69   return (struct vmm_mem_hook *)(region->host_addr);
70 }
71
72
73 /* mem_addr is the guest physical memory address */
74 static int mem_hook_dispatch(struct guest_info * info, 
75                              addr_t fault_gva, addr_t fault_gpa,  
76                              pf_error_t access_info, struct vmm_mem_hook * hook) 
77 {
78
79   // emulate and then dispatch 
80   // or dispatch and emulate
81
82
83   if (access_info.write == 1) {
84     if (v3_emulate_memory_write(info, fault_gva, hook->write, fault_gpa, hook->priv_data) == -1) {
85       PrintError("Memory write emulation failed\n");
86       return -1;
87     }
88     
89   } else {
90     if (v3_emulate_memory_read(info, fault_gva, hook->read, fault_gpa, hook->priv_data) == -1) {
91       PrintError("Memory read emulation failed\n");
92       return -1;
93     }
94   }    
95
96   return 0;
97 }
98
99
100 int handle_special_page_fault(struct guest_info * info, 
101                               addr_t fault_gva, addr_t fault_gpa, 
102                               pf_error_t access_info) 
103 {
104   struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), fault_gpa);
105
106   switch (reg->host_type) {
107   case HOST_REGION_HOOK:
108     return mem_hook_dispatch(info, fault_gva, fault_gpa, access_info, (struct vmm_mem_hook *)(reg->host_addr));
109   default:
110     return -1;
111   }
112
113   return 0;
114
115 }
116
117
118
119 void init_shadow_map(struct guest_info * info) {
120   struct shadow_map * map = &(info->mem_map);
121
122   map->num_regions = 0;
123
124   map->head = NULL;
125 }
126
127
128 void free_shadow_map(struct shadow_map * map) {
129   struct shadow_region * cursor = map->head;
130   struct shadow_region * tmp = NULL;
131
132   while(cursor) {
133     tmp = cursor;
134     cursor = cursor->next;
135     V3_Free(tmp);
136   }
137
138   V3_Free(map);
139 }
140
141
142
143
144 int add_shadow_region(struct shadow_map * map,
145                       struct shadow_region * region) 
146 {
147   struct shadow_region * cursor = map->head;
148
149   PrintDebug("Adding Shadow Region: (0x%x-0x%x)\n", region->guest_start, region->guest_end);
150
151   if ((!cursor) || (cursor->guest_start >= region->guest_end)) {
152     region->prev = NULL;
153     region->next = cursor;
154     map->num_regions++;
155     map->head = region;
156     return 0;
157   }
158
159   while (cursor) {
160     // Check if it overlaps with the current cursor
161     if ((cursor->guest_end > region->guest_start) && (cursor->guest_start < region->guest_start)) {
162       // overlaps not allowed
163       return -1;
164     }
165     
166     if (!(cursor->next)) {
167       // add to the end of the list
168       cursor->next = region;
169       region->prev = cursor;
170       region->next = NULL;
171       map->num_regions++;
172       return 0;
173     } else if (cursor->next->guest_start >= region->guest_end) {
174       // add here
175       region->next = cursor->next;
176       region->prev = cursor;
177       
178       cursor->next->prev = region;
179       cursor->next = region;
180
181       map->num_regions++;
182       
183       return 0;
184     } else if (cursor->next->guest_end <= region->guest_start) {
185       cursor = cursor->next;
186     } else {
187       // This cannot happen!
188       // we should panic here
189       return -1;
190     }
191   }
192   
193   // This cannot happen
194   // We should panic here
195   return -1;
196 }
197
198
199 int delete_shadow_region(struct shadow_map * map,
200                          addr_t guest_start,
201                          addr_t guest_end) {
202   return -1;
203 }
204
205
206
207 struct shadow_region *get_shadow_region_by_index(struct shadow_map *  map,
208                                                  uint_t index) {
209   struct shadow_region * reg = map->head;
210   uint_t i = 0;
211
212   while (reg) { 
213     if (i == index) { 
214       return reg;
215     }
216     reg = reg->next;
217     i++;
218   }
219   return NULL;
220 }
221
222
223 struct shadow_region * get_shadow_region_by_addr(struct shadow_map * map,
224                                                  addr_t addr) {
225   struct shadow_region * reg = map->head;
226
227   while (reg) {
228     if ((reg->guest_start <= addr) && (reg->guest_end > addr)) {
229       return reg;
230     } else if (reg->guest_start > addr) {
231       return NULL;
232     } else {
233       reg = reg->next;
234     }
235   }
236   return NULL;
237 }
238
239
240 host_region_type_t get_shadow_addr_type(struct guest_info * info, addr_t guest_addr) {
241   struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), guest_addr);
242
243   if (!reg) {
244     return HOST_REGION_INVALID;
245   } else {
246     return reg->host_type;
247   }
248 }
249
250 addr_t get_shadow_addr(struct guest_info * info, addr_t guest_addr) {
251   struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), guest_addr);
252
253   if (!reg) {
254     return 0;
255   } else {
256     return (guest_addr - reg->guest_start) + reg->host_addr;
257   }
258 }
259
260
261 host_region_type_t lookup_shadow_map_addr(struct shadow_map * map, addr_t guest_addr, addr_t * host_addr) {
262   struct shadow_region * reg = get_shadow_region_by_addr(map, guest_addr);
263
264   if (!reg) {
265     // No mapping exists
266     return HOST_REGION_INVALID;
267   } else {
268     switch (reg->host_type) {
269     case HOST_REGION_PHYSICAL_MEMORY:
270      *host_addr = (guest_addr - reg->guest_start) + reg->host_addr;
271      return reg->host_type;
272     case HOST_REGION_MEMORY_MAPPED_DEVICE:
273     case HOST_REGION_UNALLOCATED:
274       // ... 
275     default:
276       *host_addr = 0;
277       return reg->host_type;
278     }
279   }
280 }
281
282
283 void print_shadow_map(struct shadow_map * map) {
284   struct shadow_region * cur = map->head;
285   int i = 0;
286
287   PrintDebug("Memory Layout (regions: %d) \n", map->num_regions);
288
289   while (cur) {
290     PrintDebug("%d:  0x%x - 0x%x (%s) -> ", i, cur->guest_start, cur->guest_end - 1,
291                cur->guest_type == GUEST_REGION_PHYSICAL_MEMORY ? "GUEST_REGION_PHYSICAL_MEMORY" :
292                cur->guest_type == GUEST_REGION_NOTHING ? "GUEST_REGION_NOTHING" :
293                cur->guest_type == GUEST_REGION_MEMORY_MAPPED_DEVICE ? "GUEST_REGION_MEMORY_MAPPED_DEVICE" :
294                "UNKNOWN");
295     if (cur->host_type == HOST_REGION_PHYSICAL_MEMORY || 
296         cur->host_type == HOST_REGION_UNALLOCATED ||
297         cur->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) { 
298       PrintDebug("0x%x", cur->host_addr);
299     }
300     PrintDebug("(%s)\n",
301                cur->host_type == HOST_REGION_PHYSICAL_MEMORY ? "HOST_REGION_PHYSICAL_MEMORY" :
302                cur->host_type == HOST_REGION_UNALLOCATED ? "HOST_REGION_UNALLOACTED" :
303                cur->host_type == HOST_REGION_HOOK ? "HOST_REGION_HOOK" :
304                cur->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE ? "HOST_REGION_MEMORY_MAPPED_DEVICE" :
305                cur->host_type == HOST_REGION_REMOTE ? "HOST_REGION_REMOTE" : 
306                cur->host_type == HOST_REGION_SWAPPED ? "HOST_REGION_SWAPPED" :
307                "UNKNOWN");
308     cur = cur->next;
309     i++;
310   }
311 }
312
313
314
315
316
317
318
319
320
321
322 #ifdef VMM_MEM_TEST
323
324
325 #include <stdlib.h>
326 #include <stdio.h>
327 #include <stdarg.h>
328
329
330
331
332
333 struct vmm_os_hooks * os_hooks;
334
335 void * TestMalloc(uint_t size) {
336   return malloc(size);
337 }
338
339 void * TestAllocatePages(int size) {
340   return malloc(4096 * size);
341 }
342
343
344 void TestPrint(const char * fmt, ...) {
345   va_list args;
346
347   va_start(args, fmt);
348   vprintf(fmt, args);
349   va_end(args);
350 }
351
352 int mem_list_add_test_1(  vmm_mem_list_t * list) {
353
354   uint_t offset = 0;
355
356   PrintDebug("\n\nTesting Memory List\n");
357
358   init_mem_list(list);
359
360   offset = PAGE_SIZE * 6;
361   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 10));
362   add_mem_list_pages(list, offset, 10);
363   print_mem_list(list);
364
365
366   offset = 0;
367   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + PAGE_SIZE * 4);
368   add_mem_list_pages(list, offset, 4);
369   print_mem_list(list);
370
371   offset = PAGE_SIZE * 20;
372   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 1));
373   add_mem_list_pages(list, offset, 1);
374   print_mem_list(list);
375
376   offset = PAGE_SIZE * 21;
377   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 3));
378   add_mem_list_pages(list, offset, 3);
379   print_mem_list(list);
380
381
382   offset = PAGE_SIZE * 10;
383   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 30));
384   add_mem_list_pages(list, offset, 30);
385   print_mem_list(list);
386
387
388   offset = PAGE_SIZE * 5;
389   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 1));
390   add_mem_list_pages(list, offset, 1);
391   print_mem_list(list);
392
393  
394
395   return 0;
396 }
397
398
399 int mem_layout_add_test_1(vmm_mem_layout_t * layout) {
400
401   
402   uint_t start = 0;
403   uint_t end = 0;
404
405   PrintDebug("\n\nTesting Memory Layout\n");
406
407   init_mem_layout(layout);
408
409   start = 0x6000;
410   end = 0x10000;;
411   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
412   add_guest_mem_range(layout, start, end);
413   print_mem_layout(layout);
414
415
416   start = 0x1000;
417   end = 0x3000;
418   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
419   add_guest_mem_range(layout, start, end);
420   print_mem_layout(layout);
421
422   start = 0x2000;
423   end = 0x6000;
424   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
425   add_guest_mem_range(layout, start, end);
426   print_mem_layout(layout);
427
428   start = 0x4000;
429   end = 0x5000;
430   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
431   add_guest_mem_range(layout, start, end);
432   print_mem_layout(layout);
433
434
435   start = 0x5000;
436   end = 0x7000;
437   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
438   add_guest_mem_range(layout, start, end);
439   print_mem_layout(layout);
440
441
442
443
444   return 0;
445 }
446
447
448
449 int main(int argc, char ** argv) {
450   struct vmm_os_hooks dummy_hooks;
451   os_hooks = &dummy_hooks;
452
453   vmm_mem_layout_t layout;
454   vmm_mem_list_t list;
455
456   os_hooks->malloc = &TestMalloc;
457   os_hooks->free = &free;
458   os_hooks->print_debug = &TestPrint;
459   os_hooks->allocate_pages = &TestAllocatePages;
460
461
462
463   printf("mem_list_add_test_1: %d\n", mem_list_add_test_1(&list));
464   printf("layout_add_test_1: %d\n", mem_layout_add_test_1(&layout));
465
466   return 0;
467 }
468 #endif
469
470
471
472
473
474