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.


Assorted minor fixes to the transactional memory code
[palacios.git] / palacios / src / extensions / tm_util.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) 2012, NWU EECS 441 Transactional Memory Team  
11  * Copyright (c) 2012, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author:  Maciek Swiech <dotpyfe@u.northwestern.edu>
15  *          Marcel Flores <marcel-flores@u.northwestern.edu>
16  *          Zachary Bischof <zbischof@u.northwestern.edu>
17  *          Kyle C. Hale <kh@u.northwestern.edu>
18  *
19  * This is free software.  You are permitted to use,
20  * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21  */
22
23 #include <palacios/vmm_mem.h>
24 #include <palacios/vmm.h>
25 #include <palacios/vmcb.h>
26 #include <palacios/vmm_decoder.h>
27 #include <palacios/vm_guest_mem.h>
28 #include <palacios/vmm_ctrl_regs.h>
29 #include <palacios/vmm_direct_paging.h>
30 #include <palacios/svm.h>
31 #include <palacios/vmm_excp.h>
32 #include <palacios/vmm_list.h>
33 #include <palacios/vmm_hashtable.h>
34
35 #include <extensions/trans_mem.h>
36 #include <extensions/tm_util.h>
37
38 extern void v3_stgi();
39 extern void v3_clgi();
40
41 #if !V3_CONFIG_DEBUG_TM_FUNC
42 #undef PrintDebug
43 #define PrintDebug(fmt, args...)
44 #endif
45
46 /* TM Read/Write List data structure and API *********************************
47  */
48
49 static void free_mem_op_list (struct list_head * list) {
50     struct mem_op * curr = NULL;
51     struct mem_op * tmp  = NULL;
52
53     list_for_each_entry_safe(curr, tmp, list, op_node) {
54         list_del(&(curr->op_node));
55         V3_Free(curr);
56     }
57 }
58
59
60 void v3_clear_tm_lists (struct v3_trans_mem * tm) {
61     free_mem_op_list(&(tm->trans_w_list));
62     free_mem_op_list(&(tm->trans_r_list));
63 }
64
65
66 int add_mem_op_to_list (struct list_head * list, addr_t guest_addr) {
67     struct mem_op * new;
68
69     new = list_contains_guest_addr(list, guest_addr);
70
71     if (new) {
72         new->current = 0;
73         return 0;
74     }
75
76     new = (struct mem_op *)V3_Malloc(sizeof(struct mem_op));
77     if (!new) {
78         return -1;
79     }
80
81     new->guest_addr = guest_addr;
82     new->current    = 0;
83
84     list_add_tail(&(new->op_node), list);
85
86     return 0;
87 }
88
89
90 struct mem_op * list_contains_guest_addr (struct list_head * list, addr_t guest_addr) {
91     struct mem_op * curr = NULL;
92     struct mem_op * tmp = NULL;
93
94     list_for_each_entry_safe(curr, tmp, list, op_node) {
95         if (curr->guest_addr == guest_addr) {
96             return curr;
97         }
98     }
99
100     return NULL;
101 }
102
103
104
105
106 int update_list(struct v3_trans_mem * tm, struct list_head * list) {
107     struct mem_op * curr = NULL;
108     struct mem_op * tmp  = NULL;
109     void * sp_loc;
110     addr_t v_sp_loc;
111
112     list_for_each_entry_safe(curr, tmp, list, op_node) {
113         if (!curr->current) {
114             /* we do not have the most current entry! grab it from the staging
115              * page
116              */
117             sp_loc = (void *)((addr_t)(tm->staging_page) + (curr->guest_addr % PAGE_SIZE));
118             if ((curr->guest_addr % PAGE_SIZE_4KB) > (PAGE_SIZE_4KB - 8)) {
119                 PrintError(tm->ginfo->vm_info, tm->ginfo,"++ TM UDATE LIST ++ data ref spans page boundary\n");
120                 return -1;
121             }
122
123             if (v3_hpa_to_hva((addr_t)(sp_loc), &v_sp_loc) == -1) {
124                 PrintError(tm->ginfo->vm_info, tm->ginfo,"Could not convert address on staging page to virtual address\n");
125                 return -1;
126             }
127
128             memcpy((void*)(&(curr->data)), (void*)v_sp_loc, sizeof(uint64_t));
129             curr->current = 1;
130         }
131     }
132
133     return 0;
134 }
135
136
137 int stage_entry (struct v3_trans_mem * tm, struct list_head * list, addr_t guest_addr) {
138     void * sp_loc;
139     addr_t v_sp_loc;
140     struct mem_op * curr = list_contains_guest_addr(list, guest_addr);
141
142     if (!curr) {
143         PrintDebug(tm->ginfo->vm_info, tm->ginfo,"tried to stage entry from addr %p that doesn't exist in this list\n", (void*)guest_addr);
144         return -1;
145     }
146
147     sp_loc = (void*)((addr_t)(tm->staging_page) + (guest_addr % PAGE_SIZE_4KB));
148
149     if ((curr->guest_addr % PAGE_SIZE_4KB) > (PAGE_SIZE_4KB - 8)) {
150         PrintError(tm->ginfo->vm_info, tm->ginfo,"++ TM UDATE LIST ++ data ref spans page boundary\n");
151         return -1;
152     }
153
154     if (v3_hpa_to_hva((addr_t)(sp_loc), &v_sp_loc) == -1) {
155         PrintError(tm->ginfo->vm_info, tm->ginfo,"Could not convert address on staging page to virt addr\n");
156         return -1;
157     }
158
159     /* write data back to the data page */
160     memcpy((void*)v_sp_loc,(void*)(&(curr->data)), sizeof(uint64_t));
161
162     /* mark entry as not current so we grab it back later */
163     curr->current = 0;
164     return 0;
165 }
166
167
168 int copy_add_entry(struct list_head * list, addr_t guest_addr, uint64_t data){
169     struct mem_op * new;
170
171     // Don't repeatedly add
172     new = list_contains_guest_addr(list, guest_addr);
173
174     if (new) {
175         new->current = 1;
176         new->data = data;
177     } else {
178         new = (struct mem_op*)V3_Malloc(sizeof(struct mem_op));
179
180         if (!new) {
181             return -1;
182         }
183
184         new->guest_addr = guest_addr;
185         new->current = 1;
186         new->data = data;
187         list_add_tail(&(new->op_node), list);
188     }
189     return 0;
190 }
191
192
193 int commit_list(struct guest_info * core, struct v3_trans_mem * tm) {
194     // We should not be interruptable here, needs to happen atomically
195     PrintDebug(core->vm_info, core,"-- TM COMMIT -- commiting data\n");
196     v3_clgi();
197
198     struct mem_op * curr = NULL;
199     struct mem_op * tmp  = NULL;
200
201     list_for_each_entry_safe(curr, tmp, &(tm->trans_w_list), op_node) {
202         addr_t v_ga_loc;
203         
204         if (v3_gva_to_hva(core, (addr_t)(curr->guest_addr), &v_ga_loc) == -1) {
205             PrintError(core->vm_info, core,"Could not translate gva to hva\n");
206             return -1;
207         }        
208
209         PrintDebug(core->vm_info, core,"\tValue being copied: %p\n", (void*)(curr->data));
210         memcpy((void*)v_ga_loc, (void*)(&(curr->data)) , sizeof(uint64_t));
211     }
212
213     v3_stgi();
214     return 0;
215 }
216
217
218 int v3_copy_lists(struct guest_info *core) {
219     PrintError(core->vm_info, core, "TM: unimplemented (%s)\n", __FUNCTION__);
220     return -1;
221 }
222
223
224 /* TM State functions ********************************************************
225  *
226  * int v3_set_tm(struct guest_info *core)
227  * int v3_clr_tm(struct guest_info *core)
228  * int v3_clr_vtlb(struct guest_info *core)
229  * int v3_tm_set_abrt(struct guest_info *core)
230  *
231  */
232
233 int v3_set_tm (struct v3_trans_mem * tm) {
234     struct v3_tm_state * tms = (struct v3_tm_state *)v3_get_extension_state(tm->ginfo->vm_info, "trans_mem");
235     if (tm->TM_MODE == TM_ON) {
236         PrintError(tm->ginfo->vm_info, tm->ginfo,"++ TM SET ++ tried to set tm but it was already on\n");
237         return -1;
238     }
239
240     tm->TM_MODE = TM_ON;
241     tm->TM_STATE = TM_NULL;
242
243     addr_t flags;
244     enum TM_MODE_E sys_tm;
245     
246     flags = v3_lock_irqsave(tms->lock);
247     (tms->cores_active)++;
248     sys_tm = tms->TM_MODE;
249     v3_unlock_irqrestore(tms->lock, flags);
250
251     // need to flush everyone elses VTLB to get them to start single stepping IF THEY ARENT ALREADY
252
253     if (sys_tm == TM_OFF) {
254         int core_num;
255         for (core_num = 0; core_num < tm->ginfo->vm_info->num_cores; core_num++) {
256             if (core_num == tm->ginfo->vcpu_id) {
257                 continue;
258             }
259
260             struct guest_info * r_core = &(tm->ginfo->vm_info->cores[core_num]);
261
262             // TODO: what if this happens at an inopportune time?
263             v3_clr_vtlb(r_core);
264         }
265     }
266     flags = v3_lock_irqsave(tms->lock);
267     tms->TM_MODE = TM_ON;
268     v3_unlock_irqrestore(tms->lock, flags);
269
270     return 0;
271 }
272
273 int v3_clr_tm (struct v3_trans_mem * tm) {
274     PrintDebug(tm->ginfo->vm_info, tm->ginfo,"++ CLR TM ++ clearing tm state\n");
275
276     struct v3_tm_state * tms = (struct v3_tm_state *)v3_get_extension_state(tm->ginfo->vm_info, "trans_mem");
277     tm->TM_MODE = TM_OFF;
278     tm->TM_STATE = TM_NULL;
279     tm->cur_instr_len = -1;
280
281     // last core to turn off?
282     addr_t flags;
283     int num_act;
284     
285     flags = v3_lock_irqsave(tms->lock);
286     num_act = --(tms->cores_active);
287     v3_unlock_irqrestore(tms->lock, flags);
288
289     if (num_act == 0) {
290         PrintDebug(tm->ginfo->vm_info, tm->ginfo,"++ CLR TM ++ we are the last tm->ginfo in TM, turn off system state\n");
291         tms->TM_MODE = TM_OFF;
292     }
293     return 1;
294 }
295
296 int v3_clr_vtlb (struct guest_info * core) {
297     PrintDebug(core->vm_info, core,"++ TM VTLB ++ flushing core %d's VTLB\n", core->vcpu_id);
298     v3_invalidate_shadow_pts(core);
299     return 0;
300 }
301
302 /*
303 int v3_tm_set_abrt(struct v3_trans_mem * tm) {
304     tm->TM_STATE = TM_ABORT;
305     return 0;
306 }
307 */
308
309 /* TM extra ******************************************************************
310  */
311
312 int v3_free_staging_page(struct v3_trans_mem * tm) {
313     if (!(tm->staging_page)) {
314         PrintDebug(tm->ginfo->vm_info, tm->ginfo,"++ %d : TM FREE ++ tried to dealloc null staging page\n", tm->ginfo->vcpu_id);
315         return 0;
316     }
317     V3_FreePages(tm->staging_page, 1);
318     tm->staging_page = NULL; 
319     return 0;
320 }