mirror of https://github.com/xemu-project/xemu.git
i386/xen: Add support for Xen event channel delivery to vCPU
The kvm_xen_inject_vcpu_callback_vector() function will either deliver the per-vCPU local APIC vector (as an MSI), or just kick the vCPU out of the kernel to trigger KVM's automatic delivery of the global vector. Support for asserting the GSI/PCI_INTX callbacks will come later. Also add kvm_xen_get_vcpu_info_hva() which returns the vcpu_info of a given vCPU. Signed-off-by: David Woodhouse <dwmw@amazon.co.uk> Reviewed-by: Paul Durrant <paul@xen.org>
This commit is contained in:
parent
91cce75617
commit
27d4075dd8
|
@ -21,6 +21,8 @@
|
|||
|
||||
int kvm_xen_soft_reset(void);
|
||||
uint32_t kvm_xen_get_caps(void);
|
||||
void *kvm_xen_get_vcpu_info_hva(uint32_t vcpu_id);
|
||||
void kvm_xen_inject_vcpu_callback_vector(uint32_t vcpu_id, int type);
|
||||
|
||||
#define kvm_xen_has_cap(cap) (!!(kvm_xen_get_caps() & \
|
||||
KVM_XEN_HVM_CONFIG_ ## cap))
|
||||
|
|
|
@ -1799,6 +1799,8 @@ typedef struct CPUArchState {
|
|||
#endif
|
||||
#if defined(CONFIG_KVM)
|
||||
struct kvm_nested_state *nested_state;
|
||||
MemoryRegion *xen_vcpu_info_mr;
|
||||
void *xen_vcpu_info_hva;
|
||||
uint64_t xen_vcpu_info_gpa;
|
||||
uint64_t xen_vcpu_info_default_gpa;
|
||||
uint64_t xen_vcpu_time_info_gpa;
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
#include "trace.h"
|
||||
#include "sysemu/runstate.h"
|
||||
|
||||
#include "hw/pci/msi.h"
|
||||
#include "hw/i386/apic-msidef.h"
|
||||
#include "hw/i386/kvm/xen_overlay.h"
|
||||
#include "hw/i386/kvm/xen_evtchn.h"
|
||||
|
||||
|
@ -248,6 +250,43 @@ static void do_set_vcpu_callback_vector(CPUState *cs, run_on_cpu_data data)
|
|||
}
|
||||
}
|
||||
|
||||
static int set_vcpu_info(CPUState *cs, uint64_t gpa)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
CPUX86State *env = &cpu->env;
|
||||
MemoryRegionSection mrs = { .mr = NULL };
|
||||
void *vcpu_info_hva = NULL;
|
||||
int ret;
|
||||
|
||||
ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, gpa);
|
||||
if (ret || gpa == INVALID_GPA) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
mrs = memory_region_find(get_system_memory(), gpa,
|
||||
sizeof(struct vcpu_info));
|
||||
if (mrs.mr && mrs.mr->ram_block &&
|
||||
!int128_lt(mrs.size, int128_make64(sizeof(struct vcpu_info)))) {
|
||||
vcpu_info_hva = qemu_map_ram_ptr(mrs.mr->ram_block,
|
||||
mrs.offset_within_region);
|
||||
}
|
||||
if (!vcpu_info_hva) {
|
||||
if (mrs.mr) {
|
||||
memory_region_unref(mrs.mr);
|
||||
mrs.mr = NULL;
|
||||
}
|
||||
ret = -EINVAL;
|
||||
}
|
||||
|
||||
out:
|
||||
if (env->xen_vcpu_info_mr) {
|
||||
memory_region_unref(env->xen_vcpu_info_mr);
|
||||
}
|
||||
env->xen_vcpu_info_hva = vcpu_info_hva;
|
||||
env->xen_vcpu_info_mr = mrs.mr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void do_set_vcpu_info_default_gpa(CPUState *cs, run_on_cpu_data data)
|
||||
{
|
||||
X86CPU *cpu = X86_CPU(cs);
|
||||
|
@ -257,8 +296,7 @@ static void do_set_vcpu_info_default_gpa(CPUState *cs, run_on_cpu_data data)
|
|||
|
||||
/* Changing the default does nothing if a vcpu_info was explicitly set. */
|
||||
if (env->xen_vcpu_info_gpa == INVALID_GPA) {
|
||||
kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO,
|
||||
env->xen_vcpu_info_default_gpa);
|
||||
set_vcpu_info(cs, env->xen_vcpu_info_default_gpa);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -269,8 +307,52 @@ static void do_set_vcpu_info_gpa(CPUState *cs, run_on_cpu_data data)
|
|||
|
||||
env->xen_vcpu_info_gpa = data.host_ulong;
|
||||
|
||||
kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO,
|
||||
env->xen_vcpu_info_gpa);
|
||||
set_vcpu_info(cs, env->xen_vcpu_info_gpa);
|
||||
}
|
||||
|
||||
void *kvm_xen_get_vcpu_info_hva(uint32_t vcpu_id)
|
||||
{
|
||||
CPUState *cs = qemu_get_cpu(vcpu_id);
|
||||
if (!cs) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return X86_CPU(cs)->env.xen_vcpu_info_hva;
|
||||
}
|
||||
|
||||
void kvm_xen_inject_vcpu_callback_vector(uint32_t vcpu_id, int type)
|
||||
{
|
||||
CPUState *cs = qemu_get_cpu(vcpu_id);
|
||||
uint8_t vector;
|
||||
|
||||
if (!cs) {
|
||||
return;
|
||||
}
|
||||
|
||||
vector = X86_CPU(cs)->env.xen_vcpu_callback_vector;
|
||||
if (vector) {
|
||||
/*
|
||||
* The per-vCPU callback vector injected via lapic. Just
|
||||
* deliver it as an MSI.
|
||||
*/
|
||||
MSIMessage msg = {
|
||||
.address = APIC_DEFAULT_ADDRESS | X86_CPU(cs)->apic_id,
|
||||
.data = vector | (1UL << MSI_DATA_LEVEL_SHIFT),
|
||||
};
|
||||
kvm_irqchip_send_msi(kvm_state, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case HVM_PARAM_CALLBACK_TYPE_VECTOR:
|
||||
/*
|
||||
* If the evtchn_upcall_pending field in the vcpu_info is set, then
|
||||
* KVM will automatically deliver the vector on entering the vCPU
|
||||
* so all we have to do is kick it out.
|
||||
*/
|
||||
qemu_cpu_kick(cs);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_set_vcpu_time_info_gpa(CPUState *cs, run_on_cpu_data data)
|
||||
|
@ -306,7 +388,7 @@ static void do_vcpu_soft_reset(CPUState *cs, run_on_cpu_data data)
|
|||
env->xen_vcpu_runstate_gpa = INVALID_GPA;
|
||||
env->xen_vcpu_callback_vector = 0;
|
||||
|
||||
kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, INVALID_GPA);
|
||||
set_vcpu_info(cs, INVALID_GPA);
|
||||
kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_TIME_INFO,
|
||||
INVALID_GPA);
|
||||
kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_RUNSTATE_ADDR,
|
||||
|
@ -903,7 +985,7 @@ int kvm_put_xen_state(CPUState *cs)
|
|||
}
|
||||
|
||||
if (gpa != INVALID_GPA) {
|
||||
ret = kvm_xen_set_vcpu_attr(cs, KVM_XEN_VCPU_ATTR_TYPE_VCPU_INFO, gpa);
|
||||
ret = set_vcpu_info(cs, gpa);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue