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