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.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
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.
14 * Author: Jack Lange <jacklangel@cs.pitt.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
21 #include <palacios/vmm_barrier.h>
22 #include <palacios/vmm.h>
23 #include <palacios/vm_guest.h>
25 int v3_init_barrier(struct v3_vm_info * vm_info) {
26 struct v3_barrier * barrier = &(vm_info->barrier);
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));
35 int v3_deinit_barrier(struct v3_vm_info * vm_info) {
36 struct v3_barrier * barrier = &(vm_info->barrier);
38 v3_bitmap_deinit(&(barrier->cpu_map));
39 v3_lock_deinit(&(barrier->lock));
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);
52 flag = v3_lock_irqsave(barrier->lock);
54 if (barrier->active == 0) {
59 v3_unlock_irqrestore(barrier->lock, flag);
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.
66 if (local_core != NULL) {
67 v3_wait_at_barrier(local_core);
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);
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);
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);
96 if (barrier->active == 0) {
100 // wait for barrier catch on all cores
101 while (all_blocked == 0) {
104 for (i = 0; i < vm_info->num_cores; i++) {
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) {
113 if (v3_bitmap_check(&(barrier->cpu_map), i) == 0) {
114 // There is still a core that is not waiting at the barrier
119 if (all_blocked == 1) {
123 // return immediately and spin if there is no one to yield to
124 v3_yield(local_core,-1);
132 /* Barrier synchronization primitive
133 * -- This call will block until all the guest cores are waiting at a common synchronization point
134 * in a yield loop. The core will block at the sync point until the barrier is lowered.
137 * vm_info -- The VM for which the barrier is being activated
138 * local_core -- The core whose thread this function is being called from, or NULL
139 * if the calling thread is not associated with a VM's core context
142 int v3_raise_barrier(struct v3_vm_info * vm_info, struct guest_info * local_core) {
146 if ((vm_info->run_state != VM_RUNNING) &&
147 (vm_info->run_state != VM_SIMULATING)) {
151 ret = v3_raise_barrier_nowait(vm_info, local_core);
157 return v3_wait_for_barrier(vm_info, local_core);
162 /* Lowers a barrier that has already been raised
163 * guest cores will automatically resume execution
164 * once this has been called
166 * TODO: Need someway to check that the barrier is active
169 int v3_lower_barrier(struct v3_vm_info * vm_info) {
170 struct v3_barrier * barrier = &(vm_info->barrier);
173 if ((vm_info->run_state != VM_RUNNING) &&
174 (vm_info->run_state != VM_SIMULATING)) {
178 // Clear the active flag, so cores won't wait
181 // Clear all the cpu flags, so cores will proceed
182 v3_bitmap_reset(&(barrier->cpu_map));
189 * Syncronization point for guest cores
190 * -- called as part of the main VMM event loop for each core
191 * -- if a barrier has been activated then the core will signal
192 * it has reached the barrier and sit in a yield loop until the
193 * barrier has been lowered
195 int v3_wait_at_barrier(struct guest_info * core) {
196 struct v3_barrier * barrier = &(core->vm_info->barrier);
198 if (barrier->active == 0) {
201 #ifndef V3_CONFIG_FP_SWITCH
202 v3_get_fp_state(core); // snapshot FP state now
204 # ifdef V3_CONFIG_LAZY_FP_SWITCH
205 v3_get_fp_state(core); // snapshot FP state now regardless of lazy eval
209 V3_Print(core->vm_info, core, "Core %d waiting at barrier\n", core->vcpu_id);
211 /* Barrier has been activated.
212 * Wait here until it's lowered
216 // set cpu bit in barrier bitmap
217 v3_bitmap_set(&(barrier->cpu_map), core->vcpu_id);
218 V3_Print(core->vm_info, core, "Core %d bit set as waiting\n", core->vcpu_id);
220 // wait for cpu bit to clear
221 while (v3_bitmap_check(&(barrier->cpu_map), core->vcpu_id)) {
222 // Barrier wait will spin if there is no competing work
226 #ifndef V3_CONFIG_FP_SWITCH
227 core->fp_state.need_restore=1; // restore FP on next entry
229 # ifdef V3_CONFIG_LAZY_FP_SWITCH
230 core->fp_state.need_restore=1; // restore FP on next entry