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.


working instruction emulation
[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                         shdw_region_type_t   shdw_region_type)
31 {
32   entry->guest_start = guest_addr_start;
33   entry->guest_end = guest_addr_end;
34   entry->host_type = shdw_region_type;
35   entry->host_addr = 0;
36   entry->next = entry->prev = NULL;
37 }
38
39 int add_shadow_region_passthrough( struct guest_info *  guest_info,
40                                    addr_t               guest_addr_start,
41                                    addr_t               guest_addr_end,
42                                    addr_t               host_addr)
43 {
44   struct shadow_region * entry = (struct shadow_region *)V3_Malloc(sizeof(struct shadow_region));
45
46   init_shadow_region(entry, guest_addr_start, guest_addr_end, 
47                      SHDW_REGION_ALLOCATED);
48   entry->host_addr = host_addr;
49
50   return add_shadow_region(&(guest_info->mem_map), entry);
51 }
52
53 int v3_hook_write_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end, 
54                       addr_t host_addr,
55                       int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
56                       void * priv_data) {
57
58   struct shadow_region * entry = (struct shadow_region *)V3_Malloc(sizeof(struct shadow_region));
59
60   init_shadow_region(entry, guest_addr_start, guest_addr_end, 
61                      SHDW_REGION_WRITE_HOOK);
62
63   entry->write_hook = write;
64   entry->read_hook = NULL;
65   entry->host_addr = host_addr;
66   entry->priv_data = priv_data;
67
68   return add_shadow_region(&(info->mem_map), entry);  
69 }
70
71 int v3_hook_full_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end,
72                      int (*read)(addr_t guest_addr, void * dst, uint_t length, void * priv_data),
73                      int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
74                      void * priv_data) {
75   
76   struct shadow_region * entry = (struct shadow_region *)V3_Malloc(sizeof(struct shadow_region));
77
78   init_shadow_region(entry, guest_addr_start, guest_addr_end, 
79                      SHDW_REGION_FULL_HOOK);
80
81   entry->write_hook = write;
82   entry->read_hook = read;
83   entry->priv_data = priv_data;
84
85   entry->host_addr = 0;
86
87   return add_shadow_region(&(info->mem_map), entry);
88 }
89
90
91
92
93 int handle_special_page_fault(struct guest_info * info, 
94                               addr_t fault_gva, addr_t fault_gpa, 
95                               pf_error_t access_info) 
96 {
97  struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), fault_gpa);
98
99   PrintDebug("Handling Special Page Fault\n");
100
101   switch (reg->host_type) {
102   case SHDW_REGION_WRITE_HOOK:
103     return v3_handle_mem_wr_hook(info, fault_gva, fault_gpa, reg, access_info);
104   case SHDW_REGION_FULL_HOOK:
105     return v3_handle_mem_full_hook(info, fault_gva, fault_gpa, reg, access_info);
106   default:
107     return -1;
108   }
109
110   return 0;
111
112 }
113
114 int v3_handle_mem_wr_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa, 
115                           struct shadow_region * reg, pf_error_t access_info) {
116
117   addr_t write_src_addr = 0;
118
119   int write_len = v3_emulate_write_op(info, guest_va, guest_pa, &write_src_addr);
120
121   if (write_len == -1) {
122     PrintError("Emulation failure in write hook\n");
123     return -1;
124   }
125
126
127   if (reg->write_hook(guest_pa, (void *)write_src_addr, write_len, reg->priv_data) != write_len) {
128     PrintError("Memory write hook did not return correct value\n");
129     return -1;
130   }
131
132   return 0;
133 }
134
135 int v3_handle_mem_full_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa, 
136                             struct shadow_region * reg, pf_error_t access_info) {
137   return -1;
138 }
139
140
141
142 struct shadow_region * v3_get_shadow_region(struct guest_info * info, addr_t addr) {
143   struct shadow_region * reg = info->mem_map.head;
144
145   while (reg) {
146     if ((reg->guest_start <= addr) && (reg->guest_end > addr)) {
147       return reg;
148     } else if (reg->guest_start > addr) {
149       return NULL;
150     } else {
151       reg = reg->next;
152     }
153   }
154   return NULL;
155 }
156
157
158 void init_shadow_map(struct guest_info * info) {
159   struct shadow_map * map = &(info->mem_map);
160
161   map->num_regions = 0;
162
163   map->head = NULL;
164 }
165
166
167 void free_shadow_map(struct shadow_map * map) {
168   struct shadow_region * cursor = map->head;
169   struct shadow_region * tmp = NULL;
170
171   while(cursor) {
172     tmp = cursor;
173     cursor = cursor->next;
174     V3_Free(tmp);
175   }
176
177   V3_Free(map);
178 }
179
180
181
182
183 int add_shadow_region(struct shadow_map * map,
184                       struct shadow_region * region) 
185 {
186   struct shadow_region * cursor = map->head;
187
188   PrintDebug("Adding Shadow Region: (0x%p-0x%p)\n", 
189              (void *)region->guest_start, (void *)region->guest_end);
190
191   if ((!cursor) || (cursor->guest_start >= region->guest_end)) {
192     region->prev = NULL;
193     region->next = cursor;
194     map->num_regions++;
195     map->head = region;
196     return 0;
197   }
198
199   while (cursor) {
200     // Check if it overlaps with the current cursor
201     if ((cursor->guest_end > region->guest_start) && (cursor->guest_start < region->guest_start)) {
202       // overlaps not allowed
203       return -1;
204     }
205     
206     if (!(cursor->next)) {
207       // add to the end of the list
208       cursor->next = region;
209       region->prev = cursor;
210       region->next = NULL;
211       map->num_regions++;
212       return 0;
213     } else if (cursor->next->guest_start >= region->guest_end) {
214       // add here
215       region->next = cursor->next;
216       region->prev = cursor;
217       
218       cursor->next->prev = region;
219       cursor->next = region;
220
221       map->num_regions++;
222       
223       return 0;
224     } else if (cursor->next->guest_end <= region->guest_start) {
225       cursor = cursor->next;
226     } else {
227       // This cannot happen!
228       // we should panic here
229       return -1;
230     }
231   }
232   
233   // This cannot happen
234   // We should panic here
235   return -1;
236 }
237
238
239 int delete_shadow_region(struct shadow_map * map,
240                          addr_t guest_start,
241                          addr_t guest_end) {
242   return -1;
243 }
244
245
246
247 struct shadow_region *get_shadow_region_by_index(struct shadow_map *  map,
248                                                  uint_t index) {
249   struct shadow_region * reg = map->head;
250   uint_t i = 0;
251
252   while (reg) { 
253     if (i == index) { 
254       return reg;
255     }
256     reg = reg->next;
257     i++;
258   }
259   return NULL;
260 }
261
262
263 struct shadow_region * get_shadow_region_by_addr(struct shadow_map * map,
264                                                  addr_t addr) {
265   struct shadow_region * reg = map->head;
266
267   while (reg) {
268     if ((reg->guest_start <= addr) && (reg->guest_end > addr)) {
269       return reg;
270     } else if (reg->guest_start > addr) {
271       return NULL;
272     } else {
273       reg = reg->next;
274     }
275   }
276   return NULL;
277 }
278
279
280 shdw_region_type_t get_shadow_addr_type(struct guest_info * info, addr_t guest_addr) {
281   struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), guest_addr);
282
283   if (!reg) {
284     return SHDW_REGION_INVALID;
285   } else {
286     return reg->host_type;
287   }
288 }
289
290 addr_t get_shadow_addr(struct guest_info * info, addr_t guest_addr) {
291   struct shadow_region * reg = get_shadow_region_by_addr(&(info->mem_map), guest_addr);
292
293   if (!reg) {
294     return 0;
295   } else {
296     return (guest_addr - reg->guest_start) + reg->host_addr;
297   }
298 }
299
300
301 shdw_region_type_t lookup_shadow_map_addr(struct shadow_map * map, addr_t guest_addr, addr_t * host_addr) {
302   struct shadow_region * reg = get_shadow_region_by_addr(map, guest_addr);
303
304   if (!reg) {
305     // No mapping exists
306     return SHDW_REGION_INVALID;
307   } else {
308     switch (reg->host_type) {
309     case SHDW_REGION_ALLOCATED:
310     case SHDW_REGION_WRITE_HOOK:
311      *host_addr = (guest_addr - reg->guest_start) + reg->host_addr;
312      return reg->host_type;
313     case SHDW_REGION_UNALLOCATED:
314     case SHDW_REGION_FULL_HOOK:
315       // ... 
316     default:
317       *host_addr = 0;
318       return reg->host_type;
319     }
320   }
321 }
322
323
324 void print_shadow_map(struct shadow_map * map) {
325   struct shadow_region * cur = map->head;
326   int i = 0;
327
328   PrintDebug("Memory Layout (regions: %d) \n", map->num_regions);
329
330   while (cur) {
331     PrintDebug("%d:  0x%p - 0x%p -> ", i, 
332                (void *)cur->guest_start, (void *)(cur->guest_end - 1));
333     if (cur->host_type == SHDW_REGION_ALLOCATED || 
334         cur->host_type == SHDW_REGION_UNALLOCATED) {
335       PrintDebug("0x%p", (void *)(cur->host_addr));
336     }
337     PrintDebug("(%s)\n", shdw_region_type_to_str(cur->host_type));
338     cur = cur->next;
339     i++;
340   }
341 }
342
343
344 static const uchar_t  SHDW_REGION_INVALID_STR[] = "SHDW_REGION_INVALID";
345 static const uchar_t  SHDW_REGION_WRITE_HOOK_STR[] = "SHDW_REGION_WRITE_HOOK";
346 static const uchar_t  SHDW_REGION_FULL_HOOK_STR[] = "SHDW_REGION_FULL_HOOK";
347 static const uchar_t  SHDW_REGION_ALLOCATED_STR[] = "SHDW_REGION_ALLOCATED";
348 static const uchar_t  SHDW_REGION_UNALLOCATED_STR[] = "SHDW_REGION_UNALLOCATED";
349
350
351
352 const uchar_t * shdw_region_type_to_str(shdw_region_type_t type) {
353   switch (type) {
354   case SHDW_REGION_INVALID: 
355     return SHDW_REGION_INVALID_STR;
356   case SHDW_REGION_WRITE_HOOK:
357     return SHDW_REGION_WRITE_HOOK_STR;
358   case SHDW_REGION_FULL_HOOK:
359     return SHDW_REGION_FULL_HOOK_STR;
360   case SHDW_REGION_ALLOCATED:
361     return SHDW_REGION_ALLOCATED_STR;
362   case SHDW_REGION_UNALLOCATED:
363     return SHDW_REGION_UNALLOCATED_STR;
364   default:
365     return SHDW_REGION_INVALID_STR;
366   }
367 }
368
369
370
371
372
373
374
375 #ifdef VMM_MEM_TEST
376
377
378 #include <stdlib.h>
379 #include <stdio.h>
380 #include <stdarg.h>
381
382
383
384
385
386 struct vmm_os_hooks * os_hooks;
387
388 void * TestMalloc(uint_t size) {
389   return malloc(size);
390 }
391
392 void * TestAllocatePages(int size) {
393   return malloc(4096 * size);
394 }
395
396
397 void TestPrint(const char * fmt, ...) {
398   va_list args;
399
400   va_start(args, fmt);
401   vprintf(fmt, args);
402   va_end(args);
403 }
404
405 int mem_list_add_test_1(  vmm_mem_list_t * list) {
406
407   uint_t offset = 0;
408
409   PrintDebug("\n\nTesting Memory List\n");
410
411   init_mem_list(list);
412
413   offset = PAGE_SIZE * 6;
414   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 10));
415   add_mem_list_pages(list, offset, 10);
416   print_mem_list(list);
417
418
419   offset = 0;
420   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + PAGE_SIZE * 4);
421   add_mem_list_pages(list, offset, 4);
422   print_mem_list(list);
423
424   offset = PAGE_SIZE * 20;
425   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 1));
426   add_mem_list_pages(list, offset, 1);
427   print_mem_list(list);
428
429   offset = PAGE_SIZE * 21;
430   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 3));
431   add_mem_list_pages(list, offset, 3);
432   print_mem_list(list);
433
434
435   offset = PAGE_SIZE * 10;
436   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 30));
437   add_mem_list_pages(list, offset, 30);
438   print_mem_list(list);
439
440
441   offset = PAGE_SIZE * 5;
442   PrintDebug("Adding 0x%x - 0x%x\n", offset, offset + (PAGE_SIZE * 1));
443   add_mem_list_pages(list, offset, 1);
444   print_mem_list(list);
445
446  
447
448   return 0;
449 }
450
451
452 int mem_layout_add_test_1(vmm_mem_layout_t * layout) {
453
454   
455   uint_t start = 0;
456   uint_t end = 0;
457
458   PrintDebug("\n\nTesting Memory Layout\n");
459
460   init_mem_layout(layout);
461
462   start = 0x6000;
463   end = 0x10000;;
464   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
465   add_guest_mem_range(layout, start, end);
466   print_mem_layout(layout);
467
468
469   start = 0x1000;
470   end = 0x3000;
471   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
472   add_guest_mem_range(layout, start, end);
473   print_mem_layout(layout);
474
475   start = 0x2000;
476   end = 0x6000;
477   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
478   add_guest_mem_range(layout, start, end);
479   print_mem_layout(layout);
480
481   start = 0x4000;
482   end = 0x5000;
483   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
484   add_guest_mem_range(layout, start, end);
485   print_mem_layout(layout);
486
487
488   start = 0x5000;
489   end = 0x7000;
490   PrintDebug("Adding 0x%x - 0x%x\n", start, end);
491   add_guest_mem_range(layout, start, end);
492   print_mem_layout(layout);
493
494
495
496
497   return 0;
498 }
499
500
501
502 int main(int argc, char ** argv) {
503   struct vmm_os_hooks dummy_hooks;
504   os_hooks = &dummy_hooks;
505
506   vmm_mem_layout_t layout;
507   vmm_mem_list_t list;
508
509   os_hooks->malloc = &TestMalloc;
510   os_hooks->free = &free;
511   os_hooks->print_debug = &TestPrint;
512   os_hooks->allocate_pages = &TestAllocatePages;
513
514
515
516   printf("mem_list_add_test_1: %d\n", mem_list_add_test_1(&list));
517   printf("layout_add_test_1: %d\n", mem_layout_add_test_1(&layout));
518
519   return 0;
520 }
521 #endif
522
523
524
525
526
527