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.


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