1/****************************************************************************** 2 * hypervisor.c 3 * 4 * Communication to/from hypervisor. 5 * 6 * Copyright (c) 2002-2003, K A Fraser 7 * Copyright (c) 2005, Grzegorz Milos, gm281@cam.ac.uk,Intel Research Cambridge 8 * 9 * Permission is hereby granted, free of charge, to any person obtaining a copy 10 * of this software and associated documentation files (the "Software"), to 11 * deal in the Software without restriction, including without limitation the 12 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 13 * sell copies of the Software, and to permit persons to whom the Software is 14 * furnished to do so, subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included in 17 * all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 * DEALINGS IN THE SOFTWARE. 26 */ 27 28#include <mini-os/os.h> 29#include <mini-os/lib.h> 30#include <mini-os/hypervisor.h> 31#include <mini-os/events.h> 32 33#define active_evtchns(cpu,sh,idx) \ 34 ((sh)->evtchn_pending[idx] & \ 35 ~(sh)->evtchn_mask[idx]) 36 37int _minios_in_hypervisor_callback; 38 39void _minios_do_hypervisor_callback(struct pt_regs *regs) 40{ 41 unsigned long l1, l2, l1i, l2i; 42 unsigned int port; 43 int cpu = 0; 44 shared_info_t *s = HYPERVISOR_shared_info; 45 vcpu_info_t *vcpu_info = &s->vcpu_info[cpu]; 46 47 _minios_in_hypervisor_callback = 1; 48 49 vcpu_info->evtchn_upcall_pending = 0; 50 /* NB x86. No need for a barrier here -- XCHG is a barrier on x86. */ 51#if !defined(__i386__) && !defined(__x86_64__) 52 /* Clear master flag /before/ clearing selector flag. */ 53 wmb(); 54#endif 55 l1 = xchg(&vcpu_info->evtchn_pending_sel, 0); 56 while ( l1 != 0 ) 57 { 58 l1i = __ffs(l1); 59 l1 &= ~(1UL << l1i); 60 61 while ( (l2 = active_evtchns(cpu, s, l1i)) != 0 ) 62 { 63 l2i = __ffs(l2); 64 l2 &= ~(1UL << l2i); 65 66 port = (l1i * (sizeof(unsigned long) * 8)) + l2i; 67 do_event(port, regs); 68 } 69 } 70 71 _minios_in_hypervisor_callback = 0; 72} 73 74void minios_force_evtchn_callback(void) 75{ 76 int save; 77 vcpu_info_t *vcpu; 78 vcpu = &HYPERVISOR_shared_info->vcpu_info[smp_processor_id()]; 79 save = vcpu->evtchn_upcall_mask; 80 81 while (vcpu->evtchn_upcall_pending) { 82 vcpu->evtchn_upcall_mask = 1; 83 barrier(); 84 _minios_do_hypervisor_callback(NULL); 85 barrier(); 86 vcpu->evtchn_upcall_mask = save; 87 barrier(); 88 }; 89} 90 91inline void minios_mask_evtchn(uint32_t port) 92{ 93 shared_info_t *s = HYPERVISOR_shared_info; 94 synch_set_bit(port, &s->evtchn_mask[0]); 95} 96 97inline void minios_unmask_evtchn(uint32_t port) 98{ 99 shared_info_t *s = HYPERVISOR_shared_info; 100 vcpu_info_t *vcpu_info = &s->vcpu_info[smp_processor_id()]; 101 102 synch_clear_bit(port, &s->evtchn_mask[0]); 103 104 /* 105 * The following is basically the equivalent of 'hw_resend_irq'. Just like 106 * a real IO-APIC we 'lose the interrupt edge' if the channel is masked. 107 */ 108 if ( synch_test_bit (port, &s->evtchn_pending[0]) && 109 !synch_test_and_set_bit(port / (sizeof(unsigned long) * 8), 110 &vcpu_info->evtchn_pending_sel) ) 111 { 112 vcpu_info->evtchn_upcall_pending = 1; 113 if ( !vcpu_info->evtchn_upcall_mask ) 114 minios_force_evtchn_callback(); 115 } 116} 117 118inline void minios_clear_evtchn(uint32_t port) 119{ 120 shared_info_t *s = HYPERVISOR_shared_info; 121 synch_clear_bit(port, &s->evtchn_pending[0]); 122} 123 124int minios_hypercall(unsigned op, unsigned long a0, 125 unsigned long a1, unsigned long a2, 126 unsigned long a3, unsigned long a4) 127{ 128 multicall_entry_t call; 129 int ret; 130 131 call.op = op; 132 call.args[0] = a0; 133 call.args[1] = a1; 134 call.args[2] = a2; 135 call.args[3] = a3; 136 call.args[4] = a4; 137 138 ret = HYPERVISOR_multicall(&call, 1); 139 140 return ret; 141} 142