1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * ARM Generic Interrupt Controller (GIC) v3 host support 4 */ 5 6 #include <linux/kvm.h> 7 #include <linux/sizes.h> 8 #include <asm/kvm.h> 9 10 #include "kvm_util.h" 11 #include "../kvm_util_internal.h" 12 #include "vgic.h" 13 14 /* 15 * vGIC-v3 default host setup 16 * 17 * Input args: 18 * vm - KVM VM 19 * nr_vcpus - Number of vCPUs supported by this VM 20 * gicd_base_gpa - Guest Physical Address of the Distributor region 21 * gicr_base_gpa - Guest Physical Address of the Redistributor region 22 * 23 * Output args: None 24 * 25 * Return: GIC file-descriptor or negative error code upon failure 26 * 27 * The function creates a vGIC-v3 device and maps the distributor and 28 * redistributor regions of the guest. Since it depends on the number of 29 * vCPUs for the VM, it must be called after all the vCPUs have been created. 30 */ 31 int vgic_v3_setup(struct kvm_vm *vm, unsigned int nr_vcpus, 32 uint64_t gicd_base_gpa, uint64_t gicr_base_gpa) 33 { 34 int gic_fd; 35 uint64_t redist_attr; 36 struct list_head *iter; 37 unsigned int nr_gic_pages, nr_vcpus_created = 0; 38 39 TEST_ASSERT(nr_vcpus, "Number of vCPUs cannot be empty\n"); 40 41 /* 42 * Make sure that the caller is infact calling this 43 * function after all the vCPUs are added. 44 */ 45 list_for_each(iter, &vm->vcpus) 46 nr_vcpus_created++; 47 TEST_ASSERT(nr_vcpus == nr_vcpus_created, 48 "Number of vCPUs requested (%u) doesn't match with the ones created for the VM (%u)\n", 49 nr_vcpus, nr_vcpus_created); 50 51 /* Distributor setup */ 52 gic_fd = kvm_create_device(vm, KVM_DEV_TYPE_ARM_VGIC_V3, false); 53 kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, 54 KVM_VGIC_V3_ADDR_TYPE_DIST, &gicd_base_gpa, true); 55 nr_gic_pages = vm_calc_num_guest_pages(vm->mode, KVM_VGIC_V3_DIST_SIZE); 56 virt_map(vm, gicd_base_gpa, gicd_base_gpa, nr_gic_pages); 57 58 /* Redistributor setup */ 59 redist_attr = REDIST_REGION_ATTR_ADDR(nr_vcpus, gicr_base_gpa, 0, 0); 60 kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_ADDR, 61 KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION, &redist_attr, true); 62 nr_gic_pages = vm_calc_num_guest_pages(vm->mode, 63 KVM_VGIC_V3_REDIST_SIZE * nr_vcpus); 64 virt_map(vm, gicr_base_gpa, gicr_base_gpa, nr_gic_pages); 65 66 kvm_device_access(gic_fd, KVM_DEV_ARM_VGIC_GRP_CTRL, 67 KVM_DEV_ARM_VGIC_CTRL_INIT, NULL, true); 68 69 return gic_fd; 70 } 71