 1b2013ea5d
			
		
	
	
		1b2013ea5d
		
	
	
	
	
		
			
			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);
 |