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.


72a8b4315f7eef4677357a49d4b3a53720ec8f4c
[palacios.git] / palacios / src / palacios / vmm_sym_swap.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 #include <palacios/vmm.h>
20
21
22 #include <palacios/vmm_sym_swap.h>
23 #include <palacios/vmm_list.h>
24 #include <palacios/vm_guest.h>
25
26 #ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
27 #include <palacios/vmm_telemetry.h>
28 #endif
29
30 // This is a hack and 32 bit linux specific.... need to fix...
31 struct swap_pte {
32     uint32_t present    : 1;
33     uint32_t dev_index  : 8;
34     uint32_t pg_index   : 23;
35 };
36
37
38 struct shadow_pointer {
39     uint32_t pg_index;
40     uint32_t dev_index;
41
42     pte32_t * shadow_pte;
43     
44     addr_t guest_pte;
45     
46     struct list_head node;
47 };
48
49
50 static uint_t swap_hash_fn(addr_t key) {
51     return v3_hash_long(key, 32);
52 }
53
54
55 static int swap_eq_fn(addr_t key1, addr_t key2) {
56     return (key1 == key2);
57 }
58
59
60
61 static inline uint32_t get_pg_index(pte32_t * pte) {
62     return ((struct swap_pte *)pte)->pg_index;
63 }
64
65
66 static inline uint32_t get_dev_index(pte32_t * pte) {
67     return ((struct swap_pte *)pte)->dev_index;
68 }
69
70
71
72 #ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
73 static void telemetry_cb(struct v3_vm_info * vm, void * private_data, char * hdr) {
74     struct v3_sym_swap_state * swap_state = &(vm->swap_state);
75
76     V3_Print("%sSymbiotic Swap:\n", hdr);
77     V3_Print("%s\tRead faults=%d\n", hdr, swap_state->read_faults);
78     V3_Print("%s\tWrite faults=%d\n", hdr, swap_state->write_faults);
79     V3_Print("%s\tMapped Pages=%d\n", hdr, swap_state->mapped_pages);
80     V3_Print("%s\tFlushes=%d\n", hdr, swap_state->flushes);
81     V3_Print("%s\tlist size=%d\n", hdr, swap_state->list_size);
82 }
83 #endif
84
85
86 int v3_init_sym_swap(struct v3_vm_info * vm) {
87     struct v3_sym_swap_state * swap_state = &(vm->swap_state);
88
89     memset(swap_state, 0, sizeof(struct v3_sym_swap_state));
90     swap_state->shdw_ptr_ht = v3_create_htable(0, swap_hash_fn, swap_eq_fn);
91
92 #ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
93     if (vm->enable_telemetry) {
94         v3_add_telemetry_cb(vm, telemetry_cb, NULL);
95     }
96 #endif
97
98     PrintDebug("Initialized Symbiotic Swap\n");
99
100     return 0;
101 }
102
103
104 int v3_register_swap_disk(struct v3_vm_info * vm, int dev_index, 
105                           struct v3_swap_ops * ops, void * private_data) {
106     struct v3_sym_swap_state * swap_state = &(vm->swap_state);
107
108     swap_state->devs[dev_index].present = 1;
109     swap_state->devs[dev_index].private_data = private_data;
110     swap_state->devs[dev_index].ops = ops;
111
112     return 0;
113 }
114
115
116
117
118 int v3_swap_in_notify(struct v3_vm_info * vm, int pg_index, int dev_index) {
119     struct list_head * shdw_ptr_list = NULL;
120     struct v3_sym_swap_state * swap_state = &(vm->swap_state);
121     struct shadow_pointer * tmp_shdw_ptr = NULL;
122     struct shadow_pointer * shdw_ptr = NULL;
123     struct swap_pte guest_pte = {0, dev_index, pg_index};
124
125     shdw_ptr_list = (struct list_head * )v3_htable_search(swap_state->shdw_ptr_ht, *(addr_t *)&(guest_pte));
126
127     if (shdw_ptr_list == NULL) {
128         return 0;
129     }
130
131     list_for_each_entry_safe(shdw_ptr, tmp_shdw_ptr, shdw_ptr_list, node) {
132         if ((shdw_ptr->pg_index == pg_index) &&
133             (shdw_ptr->dev_index == dev_index)) {
134
135             // Trigger faults for next shadow access
136             shdw_ptr->shadow_pte->present = 0;
137
138             // Delete entry from list
139             list_del(&(shdw_ptr->node));
140             V3_Free(shdw_ptr);
141         }
142     }
143
144     return 0;
145 }
146
147
148
149 int v3_swap_flush(struct v3_vm_info * vm) {
150     struct v3_sym_swap_state * swap_state = &(vm->swap_state);
151     struct hashtable_iter * ht_iter = v3_create_htable_iter(swap_state->shdw_ptr_ht);
152
153     //    PrintDebug("Flushing Symbiotic Swap table\n");
154
155 #ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
156     swap_state->flushes++;
157 #endif
158
159     if (!ht_iter) {
160         PrintError("NULL iterator in swap flush!! Probably will crash soon...\n");
161     }
162
163     while (ht_iter->entry) {
164         struct shadow_pointer * tmp_shdw_ptr = NULL;
165         struct shadow_pointer * shdw_ptr = NULL;
166         struct list_head * shdw_ptr_list = (struct list_head *)v3_htable_get_iter_value(ht_iter);
167
168         // delete all swapped entries
169         // we can leave the list_head structures and reuse them for the next round
170         
171         list_for_each_entry_safe(shdw_ptr, tmp_shdw_ptr, shdw_ptr_list, node) {
172             if (shdw_ptr == NULL) {
173                 PrintError("Null shadow pointer in swap flush!! Probably crashing soon...\n");
174             }
175
176             // Trigger faults for next shadow access
177             shdw_ptr->shadow_pte->present = 0;
178             
179             // Delete entry from list
180             list_del(&(shdw_ptr->node));
181             V3_Free(shdw_ptr);
182         }
183
184         v3_htable_iter_advance(ht_iter);
185     }
186
187     V3_Free(ht_iter);
188
189     return 0;
190 }
191
192 int v3_get_vaddr_perms(struct guest_info * info, addr_t vaddr, pte32_t * guest_pte, pf_error_t * page_perms) {
193     uint64_t pte_val = (uint64_t)*(uint32_t *)guest_pte;
194
195     // symcall to check if page is in cache or on swap disk
196     if (v3_sym_call3(info, SYMCALL_MEM_LOOKUP, (uint64_t *)&vaddr, (uint64_t *)&pte_val, (uint64_t *)page_perms) == -1) {
197         PrintError("Sym call error?? that's weird... \n");
198         return -1;
199     }
200
201     //    V3_Print("page perms = %x\n", *(uint32_t *)page_perms);
202
203     if (vaddr == 0) {
204         return 1;
205     }
206
207     return 0;
208 }
209
210
211
212 addr_t v3_get_swapped_pg_addr(struct v3_vm_info * vm, pte32_t * guest_pte) {
213     struct v3_sym_swap_state * swap_state = &(vm->swap_state);
214     int dev_index = get_dev_index(guest_pte);
215     struct v3_swap_dev * swp_dev = &(swap_state->devs[dev_index]);
216
217
218     if (! swp_dev->present ) {
219         return 0;
220     }
221
222     return (addr_t)swp_dev->ops->get_swap_entry(get_pg_index(guest_pte), swp_dev->private_data);
223 }
224
225
226 addr_t v3_map_swp_page(struct v3_vm_info * vm, pte32_t * shadow_pte, pte32_t * guest_pte, void * swp_page_ptr) {
227     struct list_head * shdw_ptr_list = NULL;
228     struct v3_sym_swap_state * swap_state = &(vm->swap_state);
229     struct shadow_pointer * shdw_ptr = NULL;
230
231
232
233     if (swp_page_ptr == NULL) {
234         //      PrintError("Swapped out page not found on swap device\n");
235         return 0;
236     }
237
238     shdw_ptr_list = (struct list_head *)v3_htable_search(swap_state->shdw_ptr_ht, (addr_t)*(uint32_t *)guest_pte);
239
240     if (shdw_ptr_list == NULL) {
241         shdw_ptr_list = (struct list_head *)V3_Malloc(sizeof(struct list_head *));
242 #ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
243         swap_state->list_size++;
244 #endif
245         INIT_LIST_HEAD(shdw_ptr_list);
246         v3_htable_insert(swap_state->shdw_ptr_ht, (addr_t)*(uint32_t *)guest_pte, (addr_t)shdw_ptr_list);
247     }
248
249     shdw_ptr = (struct shadow_pointer *)V3_Malloc(sizeof(struct shadow_pointer));
250
251     if (shdw_ptr == NULL) {
252         PrintError("MEMORY LEAK\n");
253 #ifdef CONFIG_SYMBIOTIC_SWAP_TELEMETRY
254         telemetry_cb(vm, NULL, "");
255 #endif
256         return 0;
257     }
258
259     shdw_ptr->shadow_pte = shadow_pte;
260     shdw_ptr->guest_pte = *(uint32_t *)guest_pte;
261     shdw_ptr->pg_index = get_pg_index(guest_pte);
262     shdw_ptr->dev_index = get_dev_index(guest_pte);
263
264     // We don't check for conflicts, because it should not happen...
265     list_add(&(shdw_ptr->node), shdw_ptr_list);
266
267     return PAGE_BASE_ADDR((addr_t)V3_PAddr(swp_page_ptr));
268 }
269
270
271
272 /*
273 int v3_is_mapped_fault(struct guest_info * info, pte32_t * shadow_pte, pte32_t * guest_pte) {
274     struct list_head * shdw_ptr_list = NULL;
275
276     shdw_ptr_list = (struct list_head * )v3_htable_search(swap_state->shdw_ptr_ht, *(addr_t *)&(guest_pte));
277
278
279     if (shdw_ptr_list != NULL) {
280         PrintError("We faulted on a mapped in page....\n");
281         return -1;
282     }
283     
284     return 0;
285 }
286
287
288 */