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.


35efe0fb108536dce8f05d1e5f0796de4988b621
[palacios.git] / palacios / src / palacios / vmm_barrier.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) 2011, Jack Lange <jacklange@cs.pitt.edu> 
11  * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org> 
12  * All rights reserved.
13  *
14  * Author: Jack Lange <jacklangel@cs.pitt.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
21 #include <palacios/vmm_barrier.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vm_guest.h>
24
25 int v3_init_barrier(struct v3_vm_info * vm_info) {
26     struct v3_barrier * barrier = &(vm_info->barrier);
27
28     memset(barrier, 0, sizeof(struct v3_barrier));
29     v3_bitmap_init(&(barrier->cpu_map), vm_info->num_cores); 
30     v3_lock_init(&(barrier->lock));
31
32     return 0;
33 }
34
35 int v3_deinit_barrier(struct v3_vm_info * vm_info) {
36     struct v3_barrier * barrier = &(vm_info->barrier);
37
38     v3_bitmap_deinit(&(barrier->cpu_map));
39     v3_lock_deinit(&(barrier->lock));
40
41     return 0;
42 }
43
44 int v3_raise_barrier_nowait(struct v3_vm_info * vm_info, struct guest_info * local_core) {
45     struct v3_barrier * barrier = &(vm_info->barrier);
46     addr_t flag;
47     int acquired = 0;
48
49     int local_vcpu = -1;
50     int i = 0;
51
52     flag = v3_lock_irqsave(barrier->lock);
53
54     if (barrier->active == 0) {
55         barrier->active = 1;
56         acquired = 1;
57     }
58
59     v3_unlock_irqrestore(barrier->lock, flag);
60
61     if (acquired == 0) {
62         /* If we are in a core context and the barrier has already been acquired 
63            we'll be safe and let the other barrier proceed. We will still report an error 
64            though to allow possible cleanups to occur at the call site.
65         */
66         if (local_core != NULL) {
67             v3_wait_at_barrier(local_core);
68         }
69
70         return -1;
71     }
72
73     // If we are raising the barrier from a core context
74     //   we have to mark ourselves blocked first to avoid deadlock
75     if (local_core != NULL) {
76         local_vcpu = local_core->vcpu_id;
77         v3_bitmap_set(&(barrier->cpu_map), local_vcpu);
78     }
79
80
81     // send out interrupts to force exits on all cores
82     for (i = 0; i < vm_info->num_cores; i++) {
83         if (vm_info->cores[i].vcpu_id != local_vcpu) {
84             v3_interrupt_cpu(vm_info, vm_info->cores[i].pcpu_id, 0);
85         }
86     }
87
88     return 0;
89 }
90
91 int v3_wait_for_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core) {
92     struct v3_barrier * barrier = &(vm_info->barrier);
93     int all_blocked = 0;
94     int i = 0;
95
96     if (barrier->active == 0) {
97         return -1;
98     }
99
100     // wait for barrier catch on all cores
101     while (all_blocked == 0) {
102         all_blocked = 1;
103
104         for (i = 0; i < vm_info->num_cores; i++) {
105             
106             // Tricky: If a core is not running then it is safe to ignore it. 
107             // Whenever we transition a core to the RUNNING state we MUST immediately wait on the barrier. 
108             // TODO: Wrap the state transitions in functions that do this automatically
109             if (vm_info->cores[i].core_run_state != CORE_RUNNING) {
110                 continue;
111             }
112
113             if (v3_bitmap_check(&(barrier->cpu_map), i) == 0) {
114                 // There is still a core that is not waiting at the barrier
115                 all_blocked = 0;
116             }
117         }
118
119         if (all_blocked == 1) {
120             break;
121         }
122
123         v3_yield(local_core,-1);
124     }
125
126     return 0;
127 }
128
129
130
131 /* Barrier synchronization primitive
132  *   -- This call will block until all the guest cores are waiting at a common synchronization point
133  *      in a yield loop. The core will block at the sync point until the barrier is lowered.
134  * 
135  *   ARGUMENTS: 
136  *       vm_info -- The VM for which the barrier is being activated
137  *       local_core -- The core whose thread this function is being called from, or NULL 
138  *                     if the calling thread is not associated with a VM's core context
139  */
140
141 int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core) {
142     int ret = 0;
143
144
145     if ((vm_info->run_state != VM_RUNNING) && 
146         (vm_info->run_state != VM_SIMULATING)) {
147         return 0;
148     }
149
150     ret = v3_raise_barrier_nowait(vm_info, local_core);
151
152     if (ret != 0) {
153         return ret;
154     }
155
156     return v3_wait_for_barrier(vm_info, local_core);
157 }
158
159
160
161 /* Lowers a barrier that has already been raised
162  *    guest cores will automatically resume execution 
163  *    once this has been called
164  * 
165  *   TODO: Need someway to check that the barrier is active
166  */
167
168 int v3_lower_barrier(struct v3_vm_info * vm_info) {
169     struct v3_barrier * barrier = &(vm_info->barrier);
170
171     
172     if ((vm_info->run_state != VM_RUNNING) && 
173         (vm_info->run_state != VM_SIMULATING)) {
174         return 0;
175     }
176
177     // Clear the active flag, so cores won't wait 
178     barrier->active = 0;
179
180     // Clear all the cpu flags, so cores will proceed
181     v3_bitmap_reset(&(barrier->cpu_map));
182
183     return 0;
184 }
185
186
187 /* 
188  * Syncronization point for guest cores
189  *    -- called as part of the main VMM event loop for each core
190  *    -- if a barrier has been activated then the core will signal  
191  *       it has reached the barrier and sit in a yield loop until the 
192  *       barrier has been lowered
193  */
194 int v3_wait_at_barrier(struct guest_info * core) {
195     struct v3_barrier * barrier = &(core->vm_info->barrier);
196
197     if (barrier->active == 0) {
198         return 0;
199     }
200
201     V3_Print(core->vm_info, core, "Core %d waiting at barrier\n", core->vcpu_id);
202
203     /*  Barrier has been activated. 
204      *  Wait here until it's lowered
205      */
206     
207     
208     // set cpu bit in barrier bitmap
209     v3_bitmap_set(&(barrier->cpu_map), core->vcpu_id);
210     V3_Print(core->vm_info, core, "Core %d bit set as waiting\n", core->vcpu_id);
211
212     // wait for cpu bit to clear
213     while (v3_bitmap_check(&(barrier->cpu_map), core->vcpu_id)) {
214         v3_yield(core,-1);
215     }
216
217     return 0;
218 }