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