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.


fixes to the emulator to handle nested paging
[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         PrintDebug("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