In Hyper-V-related code, vCPUs are identified by their VP (virtual processor) index. Since it's customary for "vcpu_id" in QEMU to mean APIC id, rename the respective variables to "vp_index" to make the distinction clear. Signed-off-by: Roman Kagan <rkagan@virtuozzo.com> Message-Id: <20180702134156.13404-2-rkagan@virtuozzo.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
		
			
				
	
	
		
			169 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			169 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * QEMU KVM Hyper-V test device to support Hyper-V kvm-unit-tests
 | 
						|
 *
 | 
						|
 * Copyright (C) 2015 Andrey Smetanin <asmetanin@virtuozzo.com>
 | 
						|
 *
 | 
						|
 * Authors:
 | 
						|
 *  Andrey Smetanin <asmetanin@virtuozzo.com>
 | 
						|
 *
 | 
						|
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 | 
						|
 * See the COPYING file in the top-level directory.
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include "qemu/osdep.h"
 | 
						|
#include <linux/kvm.h>
 | 
						|
#include "hw/hw.h"
 | 
						|
#include "hw/qdev.h"
 | 
						|
#include "hw/isa/isa.h"
 | 
						|
#include "sysemu/kvm.h"
 | 
						|
#include "target/i386/hyperv.h"
 | 
						|
#include "kvm_i386.h"
 | 
						|
 | 
						|
#define HV_TEST_DEV_MAX_SINT_ROUTES 64
 | 
						|
 | 
						|
struct HypervTestDev {
 | 
						|
    ISADevice parent_obj;
 | 
						|
    MemoryRegion sint_control;
 | 
						|
    HvSintRoute *sint_route[HV_TEST_DEV_MAX_SINT_ROUTES];
 | 
						|
};
 | 
						|
typedef struct HypervTestDev HypervTestDev;
 | 
						|
 | 
						|
#define TYPE_HYPERV_TEST_DEV "hyperv-testdev"
 | 
						|
#define HYPERV_TEST_DEV(obj) \
 | 
						|
        OBJECT_CHECK(HypervTestDev, (obj), TYPE_HYPERV_TEST_DEV)
 | 
						|
 | 
						|
enum {
 | 
						|
    HV_TEST_DEV_SINT_ROUTE_CREATE = 1,
 | 
						|
    HV_TEST_DEV_SINT_ROUTE_DESTROY,
 | 
						|
    HV_TEST_DEV_SINT_ROUTE_SET_SINT
 | 
						|
};
 | 
						|
 | 
						|
static int alloc_sint_route_index(HypervTestDev *dev)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) {
 | 
						|
        if (dev->sint_route[i] == NULL) {
 | 
						|
            return i;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
static void free_sint_route_index(HypervTestDev *dev, int i)
 | 
						|
{
 | 
						|
    assert(i >= 0 && i < ARRAY_SIZE(dev->sint_route));
 | 
						|
    dev->sint_route[i] = NULL;
 | 
						|
}
 | 
						|
 | 
						|
static int find_sint_route_index(HypervTestDev *dev, uint32_t vp_index,
 | 
						|
                                 uint32_t sint)
 | 
						|
{
 | 
						|
    HvSintRoute *sint_route;
 | 
						|
    int i;
 | 
						|
 | 
						|
    for (i = 0; i < ARRAY_SIZE(dev->sint_route); i++) {
 | 
						|
        sint_route = dev->sint_route[i];
 | 
						|
        if (sint_route && sint_route->vp_index == vp_index &&
 | 
						|
            sint_route->sint == sint) {
 | 
						|
            return i;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
static void hv_synic_test_dev_control(HypervTestDev *dev, uint32_t ctl,
 | 
						|
                                      uint32_t vp_index, uint32_t sint)
 | 
						|
{
 | 
						|
    int i;
 | 
						|
    HvSintRoute *sint_route;
 | 
						|
 | 
						|
    switch (ctl) {
 | 
						|
    case HV_TEST_DEV_SINT_ROUTE_CREATE:
 | 
						|
        i = alloc_sint_route_index(dev);
 | 
						|
        assert(i >= 0);
 | 
						|
        sint_route = kvm_hv_sint_route_create(vp_index, sint, NULL);
 | 
						|
        assert(sint_route);
 | 
						|
        dev->sint_route[i] = sint_route;
 | 
						|
        break;
 | 
						|
    case HV_TEST_DEV_SINT_ROUTE_DESTROY:
 | 
						|
        i = find_sint_route_index(dev, vp_index, sint);
 | 
						|
        assert(i >= 0);
 | 
						|
        sint_route = dev->sint_route[i];
 | 
						|
        kvm_hv_sint_route_destroy(sint_route);
 | 
						|
        free_sint_route_index(dev, i);
 | 
						|
        break;
 | 
						|
    case HV_TEST_DEV_SINT_ROUTE_SET_SINT:
 | 
						|
        i = find_sint_route_index(dev, vp_index, sint);
 | 
						|
        assert(i >= 0);
 | 
						|
        sint_route = dev->sint_route[i];
 | 
						|
        kvm_hv_sint_route_set_sint(sint_route);
 | 
						|
        break;
 | 
						|
    default:
 | 
						|
        break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static void hv_test_dev_control(void *opaque, hwaddr addr, uint64_t data,
 | 
						|
                                uint32_t len)
 | 
						|
{
 | 
						|
    HypervTestDev *dev = HYPERV_TEST_DEV(opaque);
 | 
						|
    uint8_t ctl;
 | 
						|
 | 
						|
    ctl = (data >> 16ULL) & 0xFF;
 | 
						|
    switch (ctl) {
 | 
						|
    case HV_TEST_DEV_SINT_ROUTE_CREATE:
 | 
						|
    case HV_TEST_DEV_SINT_ROUTE_DESTROY:
 | 
						|
    case HV_TEST_DEV_SINT_ROUTE_SET_SINT: {
 | 
						|
        uint8_t sint = data & 0xFF;
 | 
						|
        uint8_t vp_index = (data >> 8ULL) & 0xFF;
 | 
						|
        hv_synic_test_dev_control(dev, ctl, vp_index, sint);
 | 
						|
        break;
 | 
						|
    }
 | 
						|
    default:
 | 
						|
        break;
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static const MemoryRegionOps synic_test_sint_ops = {
 | 
						|
    .write = hv_test_dev_control,
 | 
						|
    .valid.min_access_size = 4,
 | 
						|
    .valid.max_access_size = 4,
 | 
						|
    .endianness = DEVICE_LITTLE_ENDIAN,
 | 
						|
};
 | 
						|
 | 
						|
static void hv_test_dev_realizefn(DeviceState *d, Error **errp)
 | 
						|
{
 | 
						|
    ISADevice *isa = ISA_DEVICE(d);
 | 
						|
    HypervTestDev *dev = HYPERV_TEST_DEV(d);
 | 
						|
    MemoryRegion *io = isa_address_space_io(isa);
 | 
						|
 | 
						|
    memset(dev->sint_route, 0, sizeof(dev->sint_route));
 | 
						|
    memory_region_init_io(&dev->sint_control, OBJECT(dev),
 | 
						|
                          &synic_test_sint_ops, dev,
 | 
						|
                          "hyperv-testdev-ctl", 4);
 | 
						|
    memory_region_add_subregion(io, 0x3000, &dev->sint_control);
 | 
						|
}
 | 
						|
 | 
						|
static void hv_test_dev_class_init(ObjectClass *klass, void *data)
 | 
						|
{
 | 
						|
    DeviceClass *dc = DEVICE_CLASS(klass);
 | 
						|
 | 
						|
    set_bit(DEVICE_CATEGORY_MISC, dc->categories);
 | 
						|
    dc->realize = hv_test_dev_realizefn;
 | 
						|
}
 | 
						|
 | 
						|
static const TypeInfo hv_test_dev_info = {
 | 
						|
    .name           = TYPE_HYPERV_TEST_DEV,
 | 
						|
    .parent         = TYPE_ISA_DEVICE,
 | 
						|
    .instance_size  = sizeof(HypervTestDev),
 | 
						|
    .class_init     = hv_test_dev_class_init,
 | 
						|
};
 | 
						|
 | 
						|
static void hv_test_dev_register_types(void)
 | 
						|
{
 | 
						|
    type_register_static(&hv_test_dev_info);
 | 
						|
}
 | 
						|
type_init(hv_test_dev_register_types);
 |