Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
123 lines (106 sloc) 3.81 KB
/******************************************************************************
* hypervisor.c
*
* Communication to/from hypervisor.
*
* Copyright (c) 2002-2003, K A Fraser
* Copyright (c) 2005, Grzegorz Milos, gm281@cam.ac.uk,Intel Research Cambridge
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <mini-os/os.h>
#include <mini-os/lib.h>
#include <mini-os/hypervisor.h>
#include <mini-os/events.h>
#define active_evtchns(cpu,sh,idx) \
((sh)->evtchn_pending[idx] & \
~(sh)->evtchn_mask[idx])
int in_callback;
void do_hypervisor_callback(struct pt_regs *regs)
{
unsigned long l1, l2, l1i, l2i;
unsigned int port;
int cpu = 0;
shared_info_t *s = HYPERVISOR_shared_info;
vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
in_callback = 1;
vcpu_info->evtchn_upcall_pending = 0;
/* NB x86. No need for a barrier here -- XCHG is a barrier on x86. */
#if !defined(__i386__) && !defined(__x86_64__)
/* Clear master flag /before/ clearing selector flag. */
wmb();
#endif
l1 = xchg(&vcpu_info->evtchn_pending_sel, 0);
while ( l1 != 0 )
{
l1i = __ffs(l1);
l1 &= ~(1UL << l1i);
while ( (l2 = active_evtchns(cpu, s, l1i)) != 0 )
{
l2i = __ffs(l2);
l2 &= ~(1UL << l2i);
port = (l1i * (sizeof(unsigned long) * 8)) + l2i;
do_event(port, regs);
}
}
in_callback = 0;
}
void force_evtchn_callback(void)
{
int save;
vcpu_info_t *vcpu;
vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()];
save = vcpu->evtchn_upcall_mask;
while (vcpu->evtchn_upcall_pending) {
vcpu->evtchn_upcall_mask = 1;
barrier();
do_hypervisor_callback(NULL);
barrier();
vcpu->evtchn_upcall_mask = save;
barrier();
};
}
inline void mask_evtchn(uint32_t port)
{
shared_info_t *s = HYPERVISOR_shared_info;
synch_set_bit(port, &s->evtchn_mask[0]);
}
inline void unmask_evtchn(uint32_t port)
{
shared_info_t *s = HYPERVISOR_shared_info;
vcpu_info_t *vcpu_info = &s->vcpu_info[smp_processor_id()];
synch_clear_bit(port, &s->evtchn_mask[0]);
/*
* The following is basically the equivalent of 'hw_resend_irq'. Just like
* a real IO-APIC we 'lose the interrupt edge' if the channel is masked.
*/
if ( synch_test_bit (port, &s->evtchn_pending[0]) &&
!synch_test_and_set_bit(port / (sizeof(unsigned long) * 8),
&vcpu_info->evtchn_pending_sel) )
{
vcpu_info->evtchn_upcall_pending = 1;
if ( !vcpu_info->evtchn_upcall_mask )
force_evtchn_callback();
}
}
inline void clear_evtchn(uint32_t port)
{
shared_info_t *s = HYPERVISOR_shared_info;
synch_clear_bit(port, &s->evtchn_pending[0]);
}