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.


f887a052743418d53cd2fe615107ba218564efd6
[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     // wait for barrier catch on all cores
97     while (all_blocked == 0) {
98         all_blocked = 1;
99
100         for (i = 0; i < vm_info->num_cores; i++) {
101             
102             // Tricky: If a core is not running then it is safe to ignore it. 
103             // Whenever we transition a core to the RUNNING state we MUST immediately wait on the barrier. 
104             // TODO: Wrap the state transitions in functions that do this automatically
105             if (vm_info->cores[i].core_run_state != CORE_RUNNING) {
106                 continue;
107             }
108
109             if (v3_bitmap_check(&(barrier->cpu_map), i) == 0) {
110                 // There is still a core that is not waiting at the barrier
111                 all_blocked = 0;
112             }
113         }
114
115         if (all_blocked == 1) {
116             break;
117         }
118
119         v3_yield(local_core);
120     }
121
122     return 0;
123 }
124
125
126
127 /* Barrier synchronization primitive
128  *   -- This call will block until all the guest cores are waiting at a common synchronization point
129  *      in a yield loop. The core will block at the sync point until the barrier is lowered.
130  * 
131  *   ARGUMENTS: 
132  *       vm_info -- The VM for which the barrier is being activated
133  *       local_core -- The core whose thread this function is being called from, or NULL 
134  *                     if the calling thread is not associated with a VM's core context
135  */
136
137 int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core) {
138     int ret = 0;
139
140     ret = v3_raise_barrier_nowait(vm_info, local_core);
141
142     if (ret != 0) {
143         return ret;
144     }
145
146     return v3_wait_for_barrier(vm_info, local_core);
147 }
148
149
150
151 /* Lowers a barrier that has already been raised
152  *    guest cores will automatically resume execution 
153  *    once this has been called
154  * 
155  *   TODO: Need someway to check that the barrier is active
156  */
157
158 int v3_lower_barrier(struct v3_vm_info * vm_info) {
159     struct v3_barrier * barrier = &(vm_info->barrier);
160
161     // Clear the active flag, so cores won't wait 
162     barrier->active = 0;
163
164     // Clear all the cpu flags, so cores will proceed
165     v3_bitmap_reset(&(barrier->cpu_map));
166
167     return 0;
168 }
169
170
171 /* 
172  * Syncronization point for guest cores
173  *    -- called as part of the main VMM event loop for each core
174  *    -- if a barrier has been activated then the core will signal  
175  *       it has reached the barrier and sit in a yield loop until the 
176  *       barrier has been lowered
177  */
178 int v3_wait_at_barrier(struct guest_info * core) {
179     struct v3_barrier * barrier = &(core->vm_info->barrier);
180
181     if (barrier->active == 0) {
182         return 0;
183     }
184
185     V3_Print("Core %d waiting at barrier\n", core->vcpu_id);
186
187     /*  Barrier has been activated. 
188      *  Wait here until it's lowered
189      */
190     
191     
192     // set cpu bit in barrier bitmap
193     v3_bitmap_set(&(barrier->cpu_map), core->vcpu_id);
194     V3_Print("Core %d bit set as waiting\n", core->vcpu_id);
195
196     // wait for cpu bit to clear
197     while (v3_bitmap_check(&(barrier->cpu_map), core->vcpu_id)) {
198         v3_yield(core);
199     }
200
201     return 0;
202 }