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.


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