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 global function for searching for memory hooks
[palacios.git] / palacios / src / palacios / vmm_mem_hook.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.h>
21 #include <palacios/vm_guest.h>
22 #include <palacios/vmm_mem_hook.h>
23 #include <palacios/vmm_emulator.h>
24 #include <palacios/vm_guest_mem.h>
25
26 struct mem_hook {
27   
28     // Called when data is read from a memory page
29     int (*read)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data);
30     // Called when data is written to a memory page
31     int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data);
32
33     void * priv_data;
34     addr_t hook_hva;
35     struct v3_mem_region * region;
36
37     struct list_head hook_node;
38 };
39
40
41
42 static int free_hook(struct v3_vm_info * vm, struct mem_hook * hook);
43
44
45 int v3_init_mem_hooks(struct v3_vm_info * vm) {
46     struct v3_mem_hooks * hooks = &(vm->mem_hooks);
47
48     hooks->hook_hvas = V3_VAddr(V3_AllocPages(vm->num_cores));
49
50     INIT_LIST_HEAD(&(hooks->hook_list));
51
52     return 0;
53 }
54
55
56 // We'll assume the actual hooks were either already cleared,
57 // or will be cleared by the memory map
58 int v3_deinit_mem_hooks(struct v3_vm_info * vm) {
59     struct v3_mem_hooks * hooks = &(vm->mem_hooks);
60     struct mem_hook * hook = NULL;
61     struct mem_hook * tmp = NULL;
62
63
64     // This is nasty...
65     // We delete the hook info but leave its memory region intact
66     // We rely on the memory map to clean up any orphaned regions as a result of this
67     // This needs to be fixed at some point...
68     list_for_each_entry_safe(hook, tmp, &(hooks->hook_list), hook_node) {
69         free_hook(vm, hook);
70     }
71
72
73     V3_FreePages(V3_PAddr(hooks->hook_hvas), vm->num_cores);
74
75     return 0;
76 }
77
78
79
80
81 static int handle_mem_hook(struct guest_info * info, addr_t guest_va, addr_t guest_pa, 
82                            struct v3_mem_region * reg, pf_error_t access_info) {
83     struct mem_hook * hook = reg->priv_data;
84     struct v3_mem_hooks * hooks = &(info->vm_info->mem_hooks);
85     addr_t op_addr = 0;
86
87     if (reg->flags.alloced == 0) {
88         if (hook->hook_hva & 0xfff) {
89             op_addr = (addr_t)(hooks->hook_hvas + (PAGE_SIZE * info->cpu_id));
90         } else {
91             op_addr = hook->hook_hva;
92         }
93     } else {
94         if (v3_gpa_to_hva(info, guest_pa, &op_addr) == -1) {
95             PrintError("Could not translate hook address (%p)\n", (void *)guest_pa);
96             return -1;
97         }
98     }
99
100     
101     if (access_info.write == 1) { 
102         // Write Operation 
103         if (v3_emulate_write_op(info, guest_va, guest_pa, op_addr, 
104                                 hook->write, hook->priv_data) == -1) {
105             PrintError("Write Full Hook emulation failed\n");
106             return -1;
107         }
108     } else {
109         // Read Operation or a read->write (e.g., string ops)
110         
111         if (reg->flags.read == 1) {
112             PrintError("Tried to emulate read for a guest Readable page\n");
113             return -1;
114         }
115
116         if (v3_emulate_read_op(info, guest_va, guest_pa, op_addr, 
117                                hook->read, hook->write, 
118                                hook->priv_data) == -1) {
119             PrintError("Read Full Hook emulation failed\n");
120             return -1;
121         }
122
123     }
124
125
126     return 0;
127 }
128
129
130
131
132 int v3_hook_write_mem(struct v3_vm_info * vm, uint16_t core_id,
133                       addr_t guest_addr_start, addr_t guest_addr_end, addr_t host_addr,
134                       int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data),
135                       void * priv_data) {
136     struct v3_mem_region * entry = NULL;
137     struct mem_hook * hook = V3_Malloc(sizeof(struct mem_hook));
138     struct v3_mem_hooks * hooks = &(vm->mem_hooks);
139
140     memset(hook, 0, sizeof(struct mem_hook));
141
142     hook->write = write;
143     hook->read = NULL;
144     hook->priv_data = priv_data;
145     hook->hook_hva = (addr_t)V3_VAddr((void *)host_addr);
146
147     entry = v3_create_mem_region(vm, core_id, guest_addr_start, guest_addr_end);
148     
149     hook->region = entry;
150
151     entry->host_addr = host_addr;
152     entry->unhandled = handle_mem_hook;
153     entry->priv_data = hook;
154
155     entry->flags.read = 1;
156     entry->flags.exec = 1;
157     entry->flags.alloced = 1;
158
159     if (v3_insert_mem_region(vm, entry) == -1) {
160         V3_Free(entry);
161         V3_Free(hook);
162         return -1;
163     }
164
165     list_add(&(hook->hook_node), &(hooks->hook_list));
166
167     return 0;  
168 }
169
170
171
172 int v3_hook_full_mem(struct v3_vm_info * vm, uint16_t core_id, 
173                      addr_t guest_addr_start, addr_t guest_addr_end,
174                      int (*read)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data),
175                      int (*write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data),
176                      void * priv_data) {
177   
178     struct v3_mem_region * entry = NULL;
179     struct mem_hook * hook = V3_Malloc(sizeof(struct mem_hook));
180     struct v3_mem_hooks * hooks = &(vm->mem_hooks);
181
182     memset(hook, 0, sizeof(struct mem_hook));
183
184     hook->write = write;
185     hook->read = read;
186     hook->priv_data = priv_data;
187     hook->hook_hva = (addr_t)0xfff;
188
189     entry = v3_create_mem_region(vm, core_id, guest_addr_start, guest_addr_end);
190     hook->region = entry;
191
192     entry->unhandled = handle_mem_hook;
193     entry->priv_data = hook;
194
195     if (v3_insert_mem_region(vm, entry)) {
196         V3_Free(entry);
197         V3_Free(hook);
198         return -1;
199     }
200
201     list_add(&(hook->hook_node), &(hooks->hook_list));
202
203
204     return 0;
205 }
206
207
208 static int free_hook(struct v3_vm_info * vm, struct mem_hook * hook) {  
209     v3_delete_mem_region(vm, hook->region);
210     list_del(&(hook->hook_node));
211
212     V3_Free(hook);
213
214     return 0;
215 }
216
217
218 // This will unhook the memory hook registered at start address
219 // We do not support unhooking subregions
220 int v3_unhook_mem(struct v3_vm_info * vm, uint16_t core_id, addr_t guest_addr_start) {
221     struct v3_mem_region * reg = v3_get_mem_region(vm, core_id, guest_addr_start);
222     struct mem_hook * hook = reg->priv_data;
223
224     free_hook(vm, hook);
225
226     return 0;
227 }
228
229 // Return the read and/or write hook functions of the region associated
230 // with the address, if any.   
231 // 
232 int v3_find_mem_hook(struct v3_vm_info *vm, uint16_t core_id, addr_t guest_addr,
233                      int (**read)(struct guest_info * core, addr_t guest_addr, void * dst, uint_t length, void * priv_data),
234                      void **read_priv_data,
235                      int (**write)(struct guest_info * core, addr_t guest_addr, void * src, uint_t length, void * priv_data),
236                      void **write_priv_data)
237 {
238     struct v3_mem_region * reg = v3_get_mem_region(vm, core_id, guest_addr);
239
240     if (!reg) { 
241         return -1;
242     }
243
244     // Should probably sanity-check the region smarter than the following
245
246     struct mem_hook * hook = reg->priv_data;
247
248     if (!hook) {
249         // This must be a simple memory region without hooks
250         if (read) { *read=0;}
251         if (read_priv_data) { *read_priv_data=0;}
252         if (write) { *write=0;}
253         if (write_priv_data) { *write_priv_data=0;}
254         return 0;
255     }
256
257     // There is some form of hook here - copy it out for the caller
258     
259     if (read) { *read=hook->read;}
260     if (read_priv_data) { *read_priv_data=hook->priv_data;}
261     if (write) { *write=hook->write;}
262     if (write_priv_data) { *write_priv_data=hook->priv_data;}
263
264     return 0;
265     
266 }
267
268