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