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.


changed shadow memory map to use Red Black Tree
[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
28
29
30
31 static inline
32 struct v3_shadow_region * insert_shadow_region(struct guest_info * info, 
33                                                struct v3_shadow_region * region);
34
35
36
37 void v3_init_shadow_map(struct guest_info * info) {
38   info->mem_map.rb_node = NULL;
39 }
40
41 void v3_delete_shadow_map(struct guest_info * info) {
42   struct rb_node * node = v3_rb_first(&(info->mem_map));
43   struct v3_shadow_region * reg;
44   struct rb_node * tmp_node = NULL;
45   
46    while (node) {
47     reg = rb_entry(node, struct v3_shadow_region, tree_node);
48     tmp_node = node;
49     node = v3_rb_next(node);
50
51     v3_delete_shadow_region(info, reg);
52   }
53 }
54
55
56
57
58 int v3_add_shadow_mem( struct guest_info *  info,
59                        addr_t               guest_addr_start,
60                        addr_t               guest_addr_end,
61                        addr_t               host_addr)
62 {
63   struct v3_shadow_region * entry = (struct v3_shadow_region *)V3_Malloc(sizeof(struct v3_shadow_region));
64
65   entry->guest_start = guest_addr_start;
66   entry->guest_end = guest_addr_end;
67   entry->host_type = SHDW_REGION_ALLOCATED;
68   entry->host_addr = host_addr;
69   entry->write_hook = NULL;
70   entry->read_hook = NULL;
71   entry->priv_data = NULL;
72
73   if (insert_shadow_region(info, entry)) {
74     V3_Free(entry);
75     return -1;
76   }
77
78   return 0;
79 }
80
81
82
83 int v3_hook_write_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end, 
84                       addr_t host_addr,
85                       int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
86                       void * priv_data) {
87
88   struct v3_shadow_region * entry = (struct v3_shadow_region *)V3_Malloc(sizeof(struct v3_shadow_region));
89
90
91   entry->guest_start = guest_addr_start;
92   entry->guest_end = guest_addr_end;
93   entry->host_type = SHDW_REGION_WRITE_HOOK;
94   entry->host_addr = host_addr;
95   entry->write_hook = write;
96   entry->read_hook = NULL;
97   entry->priv_data = priv_data;
98
99   if (insert_shadow_region(info, entry)) {
100     V3_Free(entry);
101     return -1;
102   }
103
104   return 0;  
105 }
106
107 int v3_hook_full_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end,
108                      int (*read)(addr_t guest_addr, void * dst, uint_t length, void * priv_data),
109                      int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
110                      void * priv_data) {
111   
112   struct v3_shadow_region * entry = (struct v3_shadow_region *)V3_Malloc(sizeof(struct v3_shadow_region));
113
114   entry->guest_start = guest_addr_start;
115   entry->guest_end = guest_addr_end;
116   entry->host_type = SHDW_REGION_FULL_HOOK;
117   entry->host_addr = (addr_t)NULL;
118   entry->write_hook = write;
119   entry->read_hook = read;
120   entry->priv_data = priv_data;
121   
122   if (insert_shadow_region(info, entry)) {
123     V3_Free(entry);
124     return -1;
125   }
126
127   return 0;
128 }
129
130
131
132
133 static inline 
134 struct v3_shadow_region * __insert_shadow_region(struct guest_info * info, 
135                                                  struct v3_shadow_region * region) {
136   struct rb_node ** p = &(info->mem_map.rb_node);
137   struct rb_node * parent = NULL;
138   struct v3_shadow_region * tmp_region;
139
140   while (*p) {
141     parent = *p;
142     tmp_region = rb_entry(parent, struct v3_shadow_region, tree_node);
143
144     if (region->guest_end <= tmp_region->guest_start) {
145       p = &(*p)->rb_left;
146     } else if (region->guest_start >= tmp_region->guest_end) {
147       p = &(*p)->rb_right;
148     } else {
149       return tmp_region;
150     }
151   }
152
153   rb_link_node(&(region->tree_node), parent, p);
154   
155   return NULL;
156 }
157
158
159 static inline
160 struct v3_shadow_region * insert_shadow_region(struct guest_info * info, 
161                                                struct v3_shadow_region * region) {
162   struct v3_shadow_region * ret;
163
164   if ((ret = __insert_shadow_region(info, region))) {
165     return ret;
166   }
167   
168   v3_rb_insert_color(&(region->tree_node), &(info->mem_map));
169
170   return NULL;
171 }
172                                                  
173
174
175
176
177
178
179
180 int handle_special_page_fault(struct guest_info * info, 
181                               addr_t fault_gva, addr_t fault_gpa, 
182                               pf_error_t access_info) 
183 {
184  struct v3_shadow_region * reg = v3_get_shadow_region(info, fault_gpa);
185
186   PrintDebug("Handling Special Page Fault\n");
187
188   switch (reg->host_type) {
189   case SHDW_REGION_WRITE_HOOK:
190     return v3_handle_mem_wr_hook(info, fault_gva, fault_gpa, reg, access_info);
191   case SHDW_REGION_FULL_HOOK:
192     return v3_handle_mem_full_hook(info, fault_gva, fault_gpa, reg, access_info);
193   default:
194     return -1;
195   }
196
197   return 0;
198
199 }
200
201 int v3_handle_mem_wr_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa, 
202                           struct v3_shadow_region * reg, pf_error_t access_info) {
203
204   addr_t write_src_addr = 0;
205
206   int write_len = v3_emulate_write_op(info, guest_va, guest_pa, &write_src_addr);
207
208   if (write_len == -1) {
209     PrintError("Emulation failure in write hook\n");
210     return -1;
211   }
212
213
214   if (reg->write_hook(guest_pa, (void *)write_src_addr, write_len, reg->priv_data) != write_len) {
215     PrintError("Memory write hook did not return correct value\n");
216     return -1;
217   }
218
219   return 0;
220 }
221
222 int v3_handle_mem_full_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa, 
223                             struct v3_shadow_region * reg, pf_error_t access_info) {
224   return -1;
225 }
226
227
228
229 struct v3_shadow_region * v3_get_shadow_region(struct guest_info * info, addr_t guest_addr) {
230   struct rb_node * n = info->mem_map.rb_node;
231   struct v3_shadow_region * reg = NULL;
232
233   while (n) {
234     reg = rb_entry(n, struct v3_shadow_region, tree_node);
235
236     if (guest_addr < reg->guest_start) {
237       n = n->rb_left;
238     } else if (guest_addr >= reg->guest_end) {
239       n = n->rb_right;
240     } else {
241       return reg;
242     }
243   }
244
245   return NULL;
246 }
247
248
249
250 addr_t v3_get_shadow_addr(struct v3_shadow_region * reg, addr_t guest_addr) {
251   if ((reg) && 
252       (reg->host_type != SHDW_REGION_FULL_HOOK) &&
253       (reg->host_type != SHDW_REGION_INVALID)) {
254     return (guest_addr - reg->guest_start) + reg->host_addr;
255   } else {
256     PrintError("MEM Region Invalid\n");
257     return 0;
258   }
259 }
260
261
262
263 void v3_delete_shadow_region(struct guest_info * info, struct v3_shadow_region * reg) {
264   if (reg != NULL) {
265     v3_rb_erase(&(reg->tree_node), &(info->mem_map));
266
267     V3_Free(reg);
268   }
269 }
270
271
272
273
274 void print_shadow_map(struct guest_info * info) {
275   struct rb_node * node = v3_rb_first(&(info->mem_map));
276   struct v3_shadow_region * reg;
277   int i = 0;
278
279   PrintDebug("Memory Layout:\n");
280
281   do {
282     reg = rb_entry(node, struct v3_shadow_region, tree_node);
283
284     PrintDebug("%d:  0x%p - 0x%p -> 0x%p\n", i, 
285                (void *)(reg->guest_start), 
286                (void *)(reg->guest_end - 1), 
287                (void *)(reg->host_addr));
288
289     PrintDebug("\t(%s) (WriteHook = 0x%p) (ReadHook = 0x%p)\n", 
290                v3_shdw_region_type_to_str(reg->host_type),
291                (void *)(reg->write_hook), 
292                (void *)(reg->read_hook));
293     
294     i++;
295   } while ((node = v3_rb_next(node)));
296 }
297
298
299 static const uchar_t  SHDW_REGION_INVALID_STR[] = "SHDW_REGION_INVALID";
300 static const uchar_t  SHDW_REGION_WRITE_HOOK_STR[] = "SHDW_REGION_WRITE_HOOK";
301 static const uchar_t  SHDW_REGION_FULL_HOOK_STR[] = "SHDW_REGION_FULL_HOOK";
302 static const uchar_t  SHDW_REGION_ALLOCATED_STR[] = "SHDW_REGION_ALLOCATED";
303
304
305
306 const uchar_t * v3_shdw_region_type_to_str(v3_shdw_region_type_t type) {
307   switch (type) {
308   case SHDW_REGION_WRITE_HOOK:
309     return SHDW_REGION_WRITE_HOOK_STR;
310   case SHDW_REGION_FULL_HOOK:
311     return SHDW_REGION_FULL_HOOK_STR;
312   case SHDW_REGION_ALLOCATED:
313     return SHDW_REGION_ALLOCATED_STR;
314   default:
315     return SHDW_REGION_INVALID_STR;
316   }
317 }
318