hyperv: qom-ify SynIC
Make Hyper-V SynIC a device which is attached as a child to a CPU. For now it only makes SynIC visibile in the qom hierarchy, and maintains its internal fields in sync with the respecitve msrs of the parent cpu (the fields will be used in followup patches). Signed-off-by: Roman Kagan <rkagan@virtuozzo.com> Message-Id: <20180921082217.29481-3-rkagan@virtuozzo.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
729ce7e1b6
commit
606c34bfd5
@ -9,12 +9,103 @@
|
|||||||
|
|
||||||
#include "qemu/osdep.h"
|
#include "qemu/osdep.h"
|
||||||
#include "qemu/main-loop.h"
|
#include "qemu/main-loop.h"
|
||||||
|
#include "qapi/error.h"
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
#include "hw/hyperv/hyperv.h"
|
#include "hw/hyperv/hyperv.h"
|
||||||
|
|
||||||
|
typedef struct SynICState {
|
||||||
|
DeviceState parent_obj;
|
||||||
|
|
||||||
|
CPUState *cs;
|
||||||
|
|
||||||
|
bool enabled;
|
||||||
|
hwaddr msg_page_addr;
|
||||||
|
hwaddr event_page_addr;
|
||||||
|
} SynICState;
|
||||||
|
|
||||||
|
#define TYPE_SYNIC "hyperv-synic"
|
||||||
|
#define SYNIC(obj) OBJECT_CHECK(SynICState, (obj), TYPE_SYNIC)
|
||||||
|
|
||||||
|
static SynICState *get_synic(CPUState *cs)
|
||||||
|
{
|
||||||
|
return SYNIC(object_resolve_path_component(OBJECT(cs), "synic"));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void synic_update(SynICState *synic, bool enable,
|
||||||
|
hwaddr msg_page_addr, hwaddr event_page_addr)
|
||||||
|
{
|
||||||
|
|
||||||
|
synic->enabled = enable;
|
||||||
|
synic->msg_page_addr = msg_page_addr;
|
||||||
|
synic->event_page_addr = event_page_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hyperv_synic_update(CPUState *cs, bool enable,
|
||||||
|
hwaddr msg_page_addr, hwaddr event_page_addr)
|
||||||
|
{
|
||||||
|
SynICState *synic = get_synic(cs);
|
||||||
|
|
||||||
|
if (!synic) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
synic_update(synic, enable, msg_page_addr, event_page_addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void synic_realize(DeviceState *dev, Error **errp)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void synic_reset(DeviceState *dev)
|
||||||
|
{
|
||||||
|
SynICState *synic = SYNIC(dev);
|
||||||
|
synic_update(synic, false, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void synic_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->realize = synic_realize;
|
||||||
|
dc->reset = synic_reset;
|
||||||
|
dc->user_creatable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hyperv_synic_add(CPUState *cs)
|
||||||
|
{
|
||||||
|
Object *obj;
|
||||||
|
SynICState *synic;
|
||||||
|
|
||||||
|
obj = object_new(TYPE_SYNIC);
|
||||||
|
synic = SYNIC(obj);
|
||||||
|
synic->cs = cs;
|
||||||
|
object_property_add_child(OBJECT(cs), "synic", obj, &error_abort);
|
||||||
|
object_unref(obj);
|
||||||
|
object_property_set_bool(obj, true, "realized", &error_abort);
|
||||||
|
}
|
||||||
|
|
||||||
|
void hyperv_synic_reset(CPUState *cs)
|
||||||
|
{
|
||||||
|
device_reset(DEVICE(get_synic(cs)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo synic_type_info = {
|
||||||
|
.name = TYPE_SYNIC,
|
||||||
|
.parent = TYPE_DEVICE,
|
||||||
|
.instance_size = sizeof(SynICState),
|
||||||
|
.class_init = synic_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void synic_register_types(void)
|
||||||
|
{
|
||||||
|
type_register_static(&synic_type_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
type_init(synic_register_types)
|
||||||
|
|
||||||
struct HvSintRoute {
|
struct HvSintRoute {
|
||||||
uint32_t sint;
|
uint32_t sint;
|
||||||
CPUState *cs;
|
SynICState *synic;
|
||||||
int gsi;
|
int gsi;
|
||||||
EventNotifier sint_set_notifier;
|
EventNotifier sint_set_notifier;
|
||||||
EventNotifier sint_ack_notifier;
|
EventNotifier sint_ack_notifier;
|
||||||
@ -46,12 +137,18 @@ HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
|
|||||||
EventNotifier *ack_notifier;
|
EventNotifier *ack_notifier;
|
||||||
int r, gsi;
|
int r, gsi;
|
||||||
CPUState *cs;
|
CPUState *cs;
|
||||||
|
SynICState *synic;
|
||||||
|
|
||||||
cs = hyperv_find_vcpu(vp_index);
|
cs = hyperv_find_vcpu(vp_index);
|
||||||
if (!cs) {
|
if (!cs) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
synic = get_synic(cs);
|
||||||
|
if (!synic) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
sint_route = g_new0(HvSintRoute, 1);
|
sint_route = g_new0(HvSintRoute, 1);
|
||||||
r = event_notifier_init(&sint_route->sint_set_notifier, false);
|
r = event_notifier_init(&sint_route->sint_set_notifier, false);
|
||||||
if (r) {
|
if (r) {
|
||||||
@ -82,7 +179,7 @@ HvSintRoute *hyperv_sint_route_new(uint32_t vp_index, uint32_t sint,
|
|||||||
sint_route->gsi = gsi;
|
sint_route->gsi = gsi;
|
||||||
sint_route->sint_ack_clb = sint_ack_clb;
|
sint_route->sint_ack_clb = sint_ack_clb;
|
||||||
sint_route->sint_ack_clb_data = sint_ack_clb_data;
|
sint_route->sint_ack_clb_data = sint_ack_clb_data;
|
||||||
sint_route->cs = cs;
|
sint_route->synic = synic;
|
||||||
sint_route->sint = sint;
|
sint_route->sint = sint;
|
||||||
sint_route->refcount = 1;
|
sint_route->refcount = 1;
|
||||||
|
|
||||||
|
@ -28,4 +28,9 @@ static inline uint32_t hyperv_vp_index(CPUState *cs)
|
|||||||
return cs->cpu_index;
|
return cs->cpu_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hyperv_synic_add(CPUState *cs);
|
||||||
|
void hyperv_synic_reset(CPUState *cs);
|
||||||
|
void hyperv_synic_update(CPUState *cs, bool enable,
|
||||||
|
hwaddr msg_page_addr, hwaddr event_page_addr);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -33,3 +33,16 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int hyperv_x86_synic_add(X86CPU *cpu)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hyperv_x86_synic_reset(X86CPU *cpu)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void hyperv_x86_synic_update(X86CPU *cpu)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@ -16,6 +16,28 @@
|
|||||||
#include "hw/hyperv/hyperv.h"
|
#include "hw/hyperv/hyperv.h"
|
||||||
#include "hyperv-proto.h"
|
#include "hyperv-proto.h"
|
||||||
|
|
||||||
|
int hyperv_x86_synic_add(X86CPU *cpu)
|
||||||
|
{
|
||||||
|
hyperv_synic_add(CPU(cpu));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hyperv_x86_synic_reset(X86CPU *cpu)
|
||||||
|
{
|
||||||
|
hyperv_synic_reset(CPU(cpu));
|
||||||
|
}
|
||||||
|
|
||||||
|
void hyperv_x86_synic_update(X86CPU *cpu)
|
||||||
|
{
|
||||||
|
CPUX86State *env = &cpu->env;
|
||||||
|
bool enable = env->msr_hv_synic_control & HV_SYNIC_ENABLE;
|
||||||
|
hwaddr msg_page_addr = (env->msr_hv_synic_msg_page & HV_SIMP_ENABLE) ?
|
||||||
|
(env->msr_hv_synic_msg_page & TARGET_PAGE_MASK) : 0;
|
||||||
|
hwaddr event_page_addr = (env->msr_hv_synic_evt_page & HV_SIEFP_ENABLE) ?
|
||||||
|
(env->msr_hv_synic_evt_page & TARGET_PAGE_MASK) : 0;
|
||||||
|
hyperv_synic_update(CPU(cpu), enable, msg_page_addr, event_page_addr);
|
||||||
|
}
|
||||||
|
|
||||||
int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
|
int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
|
||||||
{
|
{
|
||||||
CPUX86State *env = &cpu->env;
|
CPUX86State *env = &cpu->env;
|
||||||
@ -44,6 +66,9 @@ int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit)
|
|||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hyperv_x86_synic_update(cpu);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
case KVM_EXIT_HYPERV_HCALL: {
|
case KVM_EXIT_HYPERV_HCALL: {
|
||||||
uint16_t code;
|
uint16_t code;
|
||||||
|
@ -22,4 +22,8 @@
|
|||||||
int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit);
|
int kvm_hv_handle_exit(X86CPU *cpu, struct kvm_hyperv_exit *exit);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
int hyperv_x86_synic_add(X86CPU *cpu);
|
||||||
|
void hyperv_x86_synic_reset(X86CPU *cpu);
|
||||||
|
void hyperv_x86_synic_update(X86CPU *cpu);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -790,6 +790,13 @@ static int hyperv_init_vcpu(X86CPU *cpu)
|
|||||||
strerror(-ret));
|
strerror(-ret));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = hyperv_x86_synic_add(cpu);
|
||||||
|
if (ret < 0) {
|
||||||
|
error_report("failed to create HyperV SynIC: %s",
|
||||||
|
strerror(-ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1250,6 +1257,8 @@ void kvm_arch_reset_vcpu(X86CPU *cpu)
|
|||||||
for (i = 0; i < ARRAY_SIZE(env->msr_hv_synic_sint); i++) {
|
for (i = 0; i < ARRAY_SIZE(env->msr_hv_synic_sint); i++) {
|
||||||
env->msr_hv_synic_sint[i] = HV_SINT_MASKED;
|
env->msr_hv_synic_sint[i] = HV_SINT_MASKED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hyperv_x86_synic_reset(cpu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include "hw/i386/pc.h"
|
#include "hw/i386/pc.h"
|
||||||
#include "hw/isa/isa.h"
|
#include "hw/isa/isa.h"
|
||||||
#include "migration/cpu.h"
|
#include "migration/cpu.h"
|
||||||
|
#include "hyperv.h"
|
||||||
|
|
||||||
#include "sysemu/kvm.h"
|
#include "sysemu/kvm.h"
|
||||||
|
|
||||||
@ -672,11 +673,19 @@ static bool hyperv_synic_enable_needed(void *opaque)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int hyperv_synic_post_load(void *opaque, int version_id)
|
||||||
|
{
|
||||||
|
X86CPU *cpu = opaque;
|
||||||
|
hyperv_x86_synic_update(cpu);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static const VMStateDescription vmstate_msr_hyperv_synic = {
|
static const VMStateDescription vmstate_msr_hyperv_synic = {
|
||||||
.name = "cpu/msr_hyperv_synic",
|
.name = "cpu/msr_hyperv_synic",
|
||||||
.version_id = 1,
|
.version_id = 1,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 1,
|
||||||
.needed = hyperv_synic_enable_needed,
|
.needed = hyperv_synic_enable_needed,
|
||||||
|
.post_load = hyperv_synic_post_load,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT64(env.msr_hv_synic_control, X86CPU),
|
VMSTATE_UINT64(env.msr_hv_synic_control, X86CPU),
|
||||||
VMSTATE_UINT64(env.msr_hv_synic_evt_page, X86CPU),
|
VMSTATE_UINT64(env.msr_hv_synic_evt_page, X86CPU),
|
||||||
|
Loading…
Reference in New Issue
Block a user