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.


cleaned up the memory handing implementation
[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_emulator.h>
24
25
26 #define MEM_OFFSET_HCALL 0x1000
27
28
29 static inline
30 struct v3_shadow_region * insert_shadow_region(struct guest_info * info, 
31                                                struct v3_shadow_region * region);
32
33
34 static int mem_offset_hypercall(struct guest_info * info, uint_t hcall_id, void * private_data) {
35     info->vm_regs.rbx = info->mem_map.base_region.host_addr;
36
37     return 0;
38 }
39
40
41 void v3_init_shadow_map(struct guest_info * info) {
42     v3_shdw_map_t * map = &(info->mem_map);
43     addr_t mem_pages = info->mem_size >> 12;
44
45     map->shdw_regions.rb_node = NULL;
46     map->hook_hva = (addr_t)V3_VAddr(V3_AllocPages(1));
47
48     // There is an underlying region that contains all of the guest memory
49     map->base_region.guest_start = 0;
50     map->base_region.guest_end = info->mem_size;
51     map->base_region.host_type = SHDW_REGION_ALLOCATED;
52     map->base_region.host_addr = (addr_t)V3_AllocPages(mem_pages);
53
54     v3_register_hypercall(info, MEM_OFFSET_HCALL, mem_offset_hypercall, NULL);
55 }
56
57 void v3_delete_shadow_map(struct guest_info * info) {
58     struct rb_node * node = v3_rb_first(&(info->mem_map.shdw_regions));
59     struct v3_shadow_region * reg;
60     struct rb_node * tmp_node = NULL;
61   
62     while (node) {
63         reg = rb_entry(node, struct v3_shadow_region, tree_node);
64         tmp_node = node;
65         node = v3_rb_next(node);
66
67         v3_delete_shadow_region(info, reg);
68     }
69
70     V3_FreePage((void *)(info->mem_map.base_region.host_addr));
71     V3_FreePage(V3_PAddr((void *)(info->mem_map.hook_hva)));
72 }
73
74
75
76
77 int v3_add_shadow_mem( struct guest_info *  info,
78                        addr_t               guest_addr_start,
79                        addr_t               guest_addr_end,
80                        addr_t               host_addr)
81 {
82     struct v3_shadow_region * entry = (struct v3_shadow_region *)V3_Malloc(sizeof(struct v3_shadow_region));
83
84     entry->guest_start = guest_addr_start;
85     entry->guest_end = guest_addr_end;
86     entry->host_type = SHDW_REGION_ALLOCATED;
87     entry->host_addr = host_addr;
88     entry->write_hook = NULL;
89     entry->read_hook = NULL;
90     entry->priv_data = NULL;
91
92     if (insert_shadow_region(info, entry)) {
93         V3_Free(entry);
94         return -1;
95     }
96
97     return 0;
98 }
99
100
101
102 int v3_hook_write_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end, 
103                       addr_t host_addr,
104                       int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
105                       void * priv_data) {
106
107     struct v3_shadow_region * entry = (struct v3_shadow_region *)V3_Malloc(sizeof(struct v3_shadow_region));
108
109
110     entry->guest_start = guest_addr_start;
111     entry->guest_end = guest_addr_end;
112     entry->host_type = SHDW_REGION_WRITE_HOOK;
113     entry->host_addr = host_addr;
114     entry->write_hook = write;
115     entry->read_hook = NULL;
116     entry->priv_data = priv_data;
117
118     if (insert_shadow_region(info, entry)) {
119         V3_Free(entry);
120         return -1;
121     }
122
123     return 0;  
124 }
125
126 int v3_hook_full_mem(struct guest_info * info, addr_t guest_addr_start, addr_t guest_addr_end,
127                      int (*read)(addr_t guest_addr, void * dst, uint_t length, void * priv_data),
128                      int (*write)(addr_t guest_addr, void * src, uint_t length, void * priv_data),
129                      void * priv_data) {
130   
131     struct v3_shadow_region * entry = (struct v3_shadow_region *)V3_Malloc(sizeof(struct v3_shadow_region));
132
133     entry->guest_start = guest_addr_start;
134     entry->guest_end = guest_addr_end;
135     entry->host_type = SHDW_REGION_FULL_HOOK;
136     entry->host_addr = (addr_t)NULL;
137     entry->write_hook = write;
138     entry->read_hook = read;
139     entry->priv_data = priv_data;
140   
141     if (insert_shadow_region(info, entry)) {
142         V3_Free(entry);
143         return -1;
144     }
145
146     return 0;
147 }
148
149
150
151
152 static inline 
153 struct v3_shadow_region * __insert_shadow_region(struct guest_info * info, 
154                                                  struct v3_shadow_region * region) {
155     struct rb_node ** p = &(info->mem_map.shdw_regions.rb_node);
156     struct rb_node * parent = NULL;
157     struct v3_shadow_region * tmp_region;
158
159     while (*p) {
160         parent = *p;
161         tmp_region = rb_entry(parent, struct v3_shadow_region, tree_node);
162
163         if (region->guest_end <= tmp_region->guest_start) {
164             p = &(*p)->rb_left;
165         } else if (region->guest_start >= tmp_region->guest_end) {
166             p = &(*p)->rb_right;
167         } else {
168             return tmp_region;
169         }
170     }
171
172     rb_link_node(&(region->tree_node), parent, p);
173   
174     return NULL;
175 }
176
177
178 static inline
179 struct v3_shadow_region * insert_shadow_region(struct guest_info * info, 
180                                                struct v3_shadow_region * region) {
181     struct v3_shadow_region * ret;
182
183     if ((ret = __insert_shadow_region(info, region))) {
184         return ret;
185     }
186   
187     v3_rb_insert_color(&(region->tree_node), &(info->mem_map.shdw_regions));
188
189
190     // flush virtual page tables 
191     // 3 cases shadow, shadow passthrough, and nested
192
193     return NULL;
194 }
195                                                  
196
197
198
199 int handle_special_page_fault(struct guest_info * info, 
200                               addr_t fault_gva, addr_t fault_gpa, 
201                               pf_error_t access_info) 
202 {
203     struct v3_shadow_region * reg = v3_get_shadow_region(info, fault_gpa);
204
205     PrintDebug("Handling Special Page Fault\n");
206
207     switch (reg->host_type) {
208         case SHDW_REGION_WRITE_HOOK:
209             return v3_handle_mem_wr_hook(info, fault_gva, fault_gpa, reg, access_info);
210         case SHDW_REGION_FULL_HOOK:
211             return v3_handle_mem_full_hook(info, fault_gva, fault_gpa, reg, access_info);
212         default:
213             return -1;
214     }
215
216     return 0;
217
218 }
219
220 int v3_handle_mem_wr_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa, 
221                           struct v3_shadow_region * reg, pf_error_t access_info) {
222
223     addr_t dst_addr = (addr_t)V3_VAddr((void *)v3_get_shadow_addr(reg, guest_pa));
224
225     if (v3_emulate_write_op(info, guest_va, guest_pa, dst_addr, 
226                             reg->write_hook, reg->priv_data) == -1) {
227         PrintError("Write hook emulation failed\n");
228         return -1;
229     }
230
231     return 0;
232 }
233
234 int v3_handle_mem_full_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa, 
235                             struct v3_shadow_region * reg, pf_error_t access_info) {
236   
237     addr_t op_addr = info->mem_map.hook_hva;
238
239     if (access_info.write == 1) {
240         if (v3_emulate_write_op(info, guest_va, guest_pa, op_addr, 
241                                 reg->write_hook, reg->priv_data) == -1) {
242             PrintError("Write Full Hook emulation failed\n");
243             return -1;
244         }
245     } else {
246         if (v3_emulate_read_op(info, guest_va, guest_pa, op_addr, 
247                                reg->read_hook, reg->write_hook, 
248                                reg->priv_data) == -1) {
249             PrintError("Read Full Hook emulation failed\n");
250             return -1;
251         }
252     }
253
254     return 0;
255 }
256
257
258
259 struct v3_shadow_region * v3_get_shadow_region(struct guest_info * info, addr_t guest_addr) {
260     struct rb_node * n = info->mem_map.shdw_regions.rb_node;
261     struct v3_shadow_region * reg = NULL;
262
263     while (n) {
264         reg = rb_entry(n, struct v3_shadow_region, tree_node);
265
266         if (guest_addr < reg->guest_start) {
267             n = n->rb_left;
268         } else if (guest_addr >= reg->guest_end) {
269             n = n->rb_right;
270         } else {
271             return reg;
272         }
273     }
274
275
276     // There is not registered region, so we check if its a valid address in the base region
277
278     if (guest_addr > info->mem_map.base_region.guest_end) {
279         PrintError("Guest Address Exceeds Base Memory Size (ga=%p), (limit=%p)\n", 
280                    (void *)guest_addr, (void *)info->mem_map.base_region.guest_end);
281         return NULL;
282     }
283     
284     return &(info->mem_map.base_region);
285 }
286
287
288 void v3_delete_shadow_region(struct guest_info * info, struct v3_shadow_region * reg) {
289     if (reg != NULL) {
290         v3_rb_erase(&(reg->tree_node), &(info->mem_map.shdw_regions));
291
292         V3_Free(reg);
293     }
294
295     // flush virtual page tables 
296     // 3 cases shadow, shadow passthrough, and nested
297
298 }
299
300
301
302
303 addr_t v3_get_shadow_addr(struct v3_shadow_region * reg, addr_t guest_addr) {
304     if ( (reg) && 
305          (reg->host_type != SHDW_REGION_FULL_HOOK)) {
306         return (guest_addr - reg->guest_start) + reg->host_addr;
307     } else {
308         PrintDebug("MEM Region Invalid\n");
309         return 0;
310     }
311
312 }
313
314
315
316 void print_shadow_map(struct guest_info * info) {
317     struct rb_node * node = v3_rb_first(&(info->mem_map.shdw_regions));
318     struct v3_shadow_region * reg = &(info->mem_map.base_region);
319     int i = 0;
320
321     PrintDebug("Memory Layout:\n");
322     
323
324     PrintDebug("Base Region:  0x%p - 0x%p -> 0x%p\n", 
325                (void *)(reg->guest_start), 
326                (void *)(reg->guest_end - 1), 
327                (void *)(reg->host_addr));
328     
329     do {
330         reg = rb_entry(node, struct v3_shadow_region, tree_node);
331
332         PrintDebug("%d:  0x%p - 0x%p -> 0x%p\n", i, 
333                    (void *)(reg->guest_start), 
334                    (void *)(reg->guest_end - 1), 
335                    (void *)(reg->host_addr));
336
337         PrintDebug("\t(%s) (WriteHook = 0x%p) (ReadHook = 0x%p)\n", 
338                    v3_shdw_region_type_to_str(reg->host_type),
339                    (void *)(reg->write_hook), 
340                    (void *)(reg->read_hook));
341     
342         i++;
343     } while ((node = v3_rb_next(node)));
344 }
345
346
347 static const uchar_t  SHDW_REGION_WRITE_HOOK_STR[] = "SHDW_REGION_WRITE_HOOK";
348 static const uchar_t  SHDW_REGION_FULL_HOOK_STR[] = "SHDW_REGION_FULL_HOOK";
349 static const uchar_t  SHDW_REGION_ALLOCATED_STR[] = "SHDW_REGION_ALLOCATED";
350
351 const uchar_t * v3_shdw_region_type_to_str(v3_shdw_region_type_t type) {
352     switch (type) {
353         case SHDW_REGION_WRITE_HOOK:
354             return SHDW_REGION_WRITE_HOOK_STR;
355         case SHDW_REGION_FULL_HOOK:
356             return SHDW_REGION_FULL_HOOK_STR;
357         case SHDW_REGION_ALLOCATED:
358             return SHDW_REGION_ALLOCATED_STR;
359         default:
360             return (uchar_t *)"SHDW_REGION_INVALID";
361     }
362 }
363