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.


Release 1.0
[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: %p\n", (void *)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   PrintDebug("Handling Special Page Fault\n");
126
127   switch (reg->host_type) {
128   case HOST_REGION_HOOK:
129     return mem_hook_dispatch(info, fault_gva, fault_gpa, access_info, (struct vmm_mem_hook *)(reg->host_addr));
130   default:
131     return -1;
132   }
133
134   return 0;
135
136 }
137
138
139
140 void init_shadow_map(struct guest_info * info) {
141   struct shadow_map * map = &(info->mem_map);
142
143   map->num_regions = 0;
144
145   map->head = NULL;
146 }
147
148
149 void free_shadow_map(struct shadow_map * map) {
150   struct shadow_region * cursor = map->head;
151   struct shadow_region * tmp = NULL;
152
153   while(cursor) {
154     tmp = cursor;
155     cursor = cursor->next;
156     V3_Free(tmp);
157   }
158
159   V3_Free(map);
160 }
161
162
163
164
165 int add_shadow_region(struct shadow_map * map,
166                       struct shadow_region * region) 
167 {
168   struct shadow_region * cursor = map->head;
169
170   PrintDebug("Adding Shadow Region: (0x%p-0x%p)\n", 
171              (void *)region->guest_start, (void *)region->guest_end);
172
173   if ((!cursor) || (cursor->guest_start >= region->guest_end)) {
174     region->prev = NULL;
175     region->next = cursor;
176     map->num_regions++;
177     map->head = region;
178     return 0;
179   }
180
181   while (cursor) {
182     // Check if it overlaps with the current cursor
183     if ((cursor->guest_end > region->guest_start) && (cursor->guest_start < region->guest_start)) {
184       // overlaps not allowed
185       return -1;
186     }
187     
188     if (!(cursor->next)) {
189       // add to the end of the list
190       cursor->next = region;
191       region->prev = cursor;
192       region->next = NULL;
193       map->num_regions++;
194       return 0;
195     } else if (cursor->next->guest_start >= region->guest_end) {
196       // add here
197       region->next = cursor->next;
198       region->prev = cursor;
199       
200       cursor->next->prev = region;
201       cursor->next = region;
202
203       map->num_regions++;
204       
205       return 0;
206     } else if (cursor->next->guest_end <= region->guest_start) {
207       cursor = cursor->next;
208     } else {
209       // This cannot happen!
210       // we should panic here
211       return -1;
212     }
213   }
214   
215   // This cannot happen
216   // We should panic here
217   return -1;
218 }
219
220
221 int delete_shadow_region(struct shadow_map * map,
222                          addr_t guest_start,
223                          addr_t guest_end) {
224   return -1;
225 }
226
227
228
229 struct shadow_region *get_shadow_region_by_index(struct shadow_map *  map,
230                                                  uint_t index) {
231   struct shadow_region * reg = map->head;
232   uint_t i = 0;
233
234   while (reg) { 
235     if (i == index) { 
236       return reg;
237     }
238     reg = reg->next;
239     i++;
240   }
241   return NULL;
242 }
243
244
245 struct shadow_region * get_shadow_region_by_addr(struct shadow_map * map,
246                                                  addr_t addr) {
247   struct shadow_region * reg = map->head;
248
249   while (reg) {
250     if ((reg->guest_start <= addr) && (reg->guest_end > addr)) {
251       return reg;
252     } else if (reg->guest_start > addr) {
253       return NULL;
254     } else {
255       reg = reg->next;
256     }
257   }
258   return NULL;
259 }
260
261
262 host_region_type_t get_shadow_addr_type(struct guest_info * info, addr_t guest_addr) {
263   struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), guest_addr);
264
265   if (!reg) {
266     return HOST_REGION_INVALID;
267   } else {
268     return reg->host_type;
269   }
270 }
271
272 addr_t get_shadow_addr(struct guest_info * info, addr_t guest_addr) {
273   struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), guest_addr);
274
275   if (!reg) {
276     return 0;
277   } else {
278     return (guest_addr - reg->guest_start) + reg->host_addr;
279   }
280 }
281
282
283 host_region_type_t lookup_shadow_map_addr(struct shadow_map * map, addr_t guest_addr, addr_t * host_addr) {
284   struct shadow_region * reg = get_shadow_region_by_addr(map, guest_addr);
285
286   if (!reg) {
287     // No mapping exists
288     return HOST_REGION_INVALID;
289   } else {
290     switch (reg->host_type) {
291     case HOST_REGION_PHYSICAL_MEMORY:
292      *host_addr = (guest_addr - reg->guest_start) + reg->host_addr;
293      return reg->host_type;
294     case HOST_REGION_MEMORY_MAPPED_DEVICE:
295     case HOST_REGION_UNALLOCATED:
296       // ... 
297     default:
298       *host_addr = 0;
299       return reg->host_type;
300     }
301   }
302 }
303
304
305 void print_shadow_map(struct shadow_map * map) {
306   struct shadow_region * cur = map->head;
307   int i = 0;
308
309   PrintDebug("Memory Layout (regions: %d) \n", map->num_regions);
310
311   while (cur) {
312     PrintDebug("%d:  0x%p - 0x%p (%s) -> ", i, 
313                (void *)cur->guest_start, (void *)(cur->guest_end - 1),
314                cur->guest_type == GUEST_REGION_PHYSICAL_MEMORY ? "GUEST_REGION_PHYSICAL_MEMORY" :
315                cur->guest_type == GUEST_REGION_NOTHING ? "GUEST_REGION_NOTHING" :
316                cur->guest_type == GUEST_REGION_MEMORY_MAPPED_DEVICE ? "GUEST_REGION_MEMORY_MAPPED_DEVICE" :
317                "UNKNOWN");
318     if (cur->host_type == HOST_REGION_PHYSICAL_MEMORY || 
319         cur->host_type == HOST_REGION_UNALLOCATED ||
320         cur->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE) { 
321       PrintDebug("0x%p", (void *)(cur->host_addr));
322     }
323     PrintDebug("(%s)\n",
324                cur->host_type == HOST_REGION_PHYSICAL_MEMORY ? "HOST_REGION_PHYSICAL_MEMORY" :
325                cur->host_type == HOST_REGION_UNALLOCATED ? "HOST_REGION_UNALLOACTED" :
326                cur->host_type == HOST_REGION_HOOK ? "HOST_REGION_HOOK" :
327                cur->host_type == HOST_REGION_MEMORY_MAPPED_DEVICE ? "HOST_REGION_MEMORY_MAPPED_DEVICE" :
328                cur->host_type == HOST_REGION_REMOTE ? "HOST_REGION_REMOTE" : 
329                cur->host_type == HOST_REGION_SWAPPED ? "HOST_REGION_SWAPPED" :
330                "UNKNOWN");
331     cur = cur->next;
332     i++;
333   }
334 }
335
336
337
338
339
340
341
342
343
344
345 #ifdef VMM_MEM_TEST
346
347
348 #include <stdlib.h>
349 #include <stdio.h>
350 #include <stdarg.h>
351
352
353
354
355
356 struct vmm_os_hooks * os_hooks;
357
358 void * TestMalloc(uint_t size) {
359   return malloc(size);
360 }
361
362 void * TestAllocatePages(int size) {
363   return malloc(4096 * size);
364 }
365
366
367 void TestPrint(const char * fmt, ...) {
368   va_list args;
369
370   va_start(args, fmt);
371   vprintf(fmt, args);
372   va_end(args);
373 }
374
375 int mem_list_add_test_1(  vmm_mem_list_t * list) {
376
377   uint_t offset = 0;
378
379   PrintDebug("\n\nTesting Memory List\n");
380
381   init_mem_list(list);
382
383   offset = PAGE_SIZE * 6;
384   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 10));
385   add_mem_list_pages(list, offset, 10);
386   print_mem_list(list);
387
388
389   offset = 0;
390   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + PAGE_SIZE * 4);
391   add_mem_list_pages(list, offset, 4);
392   print_mem_list(list);
393
394   offset = PAGE_SIZE * 20;
395   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 1));
396   add_mem_list_pages(list, offset, 1);
397   print_mem_list(list);
398
399   offset = PAGE_SIZE * 21;
400   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 3));
401   add_mem_list_pages(list, offset, 3);
402   print_mem_list(list);
403
404
405   offset = PAGE_SIZE * 10;
406   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 30));
407   add_mem_list_pages(list, offset, 30);
408   print_mem_list(list);
409
410
411   offset = PAGE_SIZE * 5;
412   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 1));
413   add_mem_list_pages(list, offset, 1);
414   print_mem_list(list);
415
416  
417
418   return 0;
419 }
420
421
422 int mem_layout_add_test_1(vmm_mem_layout_t * layout) {
423
424   
425   uint_t start = 0;
426   uint_t end = 0;
427
428   PrintDebug("\n\nTesting Memory Layout\n");
429
430   init_mem_layout(layout);
431
432   start = 0x6000;
433   end = 0x10000;;
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 = 0x1000;
440   end = 0x3000;
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   start = 0x2000;
446   end = 0x6000;
447   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
448   add_guest_mem_range(layout, start, end);
449   print_mem_layout(layout);
450
451   start = 0x4000;
452   end = 0x5000;
453   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
454   add_guest_mem_range(layout, start, end);
455   print_mem_layout(layout);
456
457
458   start = 0x5000;
459   end = 0x7000;
460   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
461   add_guest_mem_range(layout, start, end);
462   print_mem_layout(layout);
463
464
465
466
467   return 0;
468 }
469
470
471
472 int main(int argc, char ** argv) {
473   struct vmm_os_hooks dummy_hooks;
474   os_hooks = &dummy_hooks;
475
476   vmm_mem_layout_t layout;
477   vmm_mem_list_t list;
478
479   os_hooks->malloc = &TestMalloc;
480   os_hooks->free = &free;
481   os_hooks->print_debug = &TestPrint;
482   os_hooks->allocate_pages = &TestAllocatePages;
483
484
485
486   printf("mem_list_add_test_1: %d\n", mem_list_add_test_1(&list));
487   printf("layout_add_test_1: %d\n", mem_layout_add_test_1(&layout));
488
489   return 0;
490 }
491 #endif
492
493
494
495
496
497