Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: KVM: Initial VGIC infrastructure code

Wire the basic framework code for VGIC support and the initial in-kernel
MMIO support code for the VGIC, used for the distributor emulation.

Reviewed-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Christoffer Dall <c.dall@virtualopensystems.com>
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>

+275 -1
+8
arch/arm/include/asm/kvm_host.h
··· 37 37 #define KVM_NR_PAGE_SIZES 1 38 38 #define KVM_PAGES_PER_HPAGE(x) (1UL<<31) 39 39 40 + #include <asm/kvm_vgic.h> 41 + 40 42 struct kvm_vcpu; 41 43 u32 *kvm_vcpu_reg(struct kvm_vcpu *vcpu, u8 reg_num, u32 mode); 42 44 int kvm_target_cpu(void); ··· 60 58 61 59 /* Stage-2 page table */ 62 60 pgd_t *pgd; 61 + 62 + /* Interrupt controller */ 63 + struct vgic_dist vgic; 63 64 }; 64 65 65 66 #define KVM_NR_MEM_OBJS 40 ··· 96 91 /* Floating point registers (VFP and Advanced SIMD/NEON) */ 97 92 struct vfp_hard_struct vfp_guest; 98 93 struct vfp_hard_struct *vfp_host; 94 + 95 + /* VGIC state */ 96 + struct vgic_cpu vgic_cpu; 99 97 100 98 /* 101 99 * Anything that is not used directly from assembly code goes
+80
arch/arm/include/asm/kvm_vgic.h
··· 1 + /* 2 + * Copyright (C) 2012 ARM Ltd. 3 + * Author: Marc Zyngier <marc.zyngier@arm.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, write to the Free Software 16 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 + */ 18 + 19 + #ifndef __ASM_ARM_KVM_VGIC_H 20 + #define __ASM_ARM_KVM_VGIC_H 21 + 22 + #include <linux/irqchip/arm-gic.h> 23 + 24 + struct vgic_dist { 25 + }; 26 + 27 + struct vgic_cpu { 28 + }; 29 + 30 + struct kvm; 31 + struct kvm_vcpu; 32 + struct kvm_run; 33 + struct kvm_exit_mmio; 34 + 35 + #ifdef CONFIG_KVM_ARM_VGIC 36 + bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, 37 + struct kvm_exit_mmio *mmio); 38 + 39 + #else 40 + static inline int kvm_vgic_hyp_init(void) 41 + { 42 + return 0; 43 + } 44 + 45 + static inline int kvm_vgic_init(struct kvm *kvm) 46 + { 47 + return 0; 48 + } 49 + 50 + static inline int kvm_vgic_create(struct kvm *kvm) 51 + { 52 + return 0; 53 + } 54 + 55 + static inline int kvm_vgic_vcpu_init(struct kvm_vcpu *vcpu) 56 + { 57 + return 0; 58 + } 59 + 60 + static inline void kvm_vgic_flush_hwstate(struct kvm_vcpu *vcpu) {} 61 + static inline void kvm_vgic_sync_hwstate(struct kvm_vcpu *vcpu) {} 62 + 63 + static inline int kvm_vgic_vcpu_pending_irq(struct kvm_vcpu *vcpu) 64 + { 65 + return 0; 66 + } 67 + 68 + static inline bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, 69 + struct kvm_exit_mmio *mmio) 70 + { 71 + return false; 72 + } 73 + 74 + static inline int irqchip_in_kernel(struct kvm *kvm) 75 + { 76 + return 0; 77 + } 78 + #endif 79 + 80 + #endif
+1
arch/arm/kvm/Makefile
··· 19 19 obj-y += kvm-arm.o init.o interrupts.o 20 20 obj-y += arm.o guest.o mmu.o emulate.o reset.o 21 21 obj-y += coproc.o coproc_a15.o mmio.o psci.o 22 + obj-$(CONFIG_KVM_ARM_VGIC) += vgic.o
+26 -1
arch/arm/kvm/arm.c
··· 62 62 static u8 kvm_next_vmid; 63 63 static DEFINE_SPINLOCK(kvm_vmid_lock); 64 64 65 + static bool vgic_present; 66 + 65 67 static void kvm_arm_set_running_vcpu(struct kvm_vcpu *vcpu) 66 68 { 67 69 BUG_ON(preemptible()); ··· 186 184 { 187 185 int r; 188 186 switch (ext) { 187 + case KVM_CAP_IRQCHIP: 188 + r = vgic_present; 189 + break; 189 190 case KVM_CAP_USER_MEMORY: 190 191 case KVM_CAP_SYNC_MMU: 191 192 case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: ··· 320 315 321 316 int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) 322 317 { 318 + int ret; 319 + 323 320 /* Force users to call KVM_ARM_VCPU_INIT */ 324 321 vcpu->arch.target = -1; 322 + 323 + /* Set up VGIC */ 324 + ret = kvm_vgic_vcpu_init(vcpu); 325 + if (ret) 326 + return ret; 327 + 325 328 return 0; 326 329 } 327 330 ··· 387 374 */ 388 375 int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) 389 376 { 390 - return !!v->arch.irq_lines; 377 + return !!v->arch.irq_lines || kvm_vgic_vcpu_pending_irq(v); 391 378 } 392 379 393 380 /* Just ensure a guest exit from a particular CPU */ ··· 706 693 if (vcpu->arch.pause) 707 694 vcpu_pause(vcpu); 708 695 696 + kvm_vgic_flush_hwstate(vcpu); 697 + 709 698 local_irq_disable(); 710 699 711 700 /* ··· 720 705 721 706 if (ret <= 0 || need_new_vmid_gen(vcpu->kvm)) { 722 707 local_irq_enable(); 708 + kvm_vgic_sync_hwstate(vcpu); 723 709 continue; 724 710 } 725 711 ··· 752 736 /* 753 737 * Back from guest 754 738 *************************************************************/ 739 + 740 + kvm_vgic_sync_hwstate(vcpu); 755 741 756 742 ret = handle_exit(vcpu, run, ret); 757 743 } ··· 1028 1010 goto out_free_vfp; 1029 1011 } 1030 1012 } 1013 + 1014 + /* 1015 + * Init HYP view of VGIC 1016 + */ 1017 + err = kvm_vgic_hyp_init(); 1018 + if (err) 1019 + goto out_free_vfp; 1031 1020 1032 1021 kvm_info("Hyp mode initialized successfully\n"); 1033 1022 return 0;
+4
arch/arm/kvm/interrupts.S
··· 94 94 95 95 save_host_regs 96 96 97 + restore_vgic_state 98 + 97 99 @ Store hardware CP15 state and load guest state 98 100 read_cp15_state store_to_vcpu = 0 99 101 write_cp15_state read_from_vcpu = 1 ··· 188 186 @ Store guest CP15 state and restore host state 189 187 read_cp15_state store_to_vcpu = 1 190 188 write_cp15_state read_from_vcpu = 0 189 + 190 + save_vgic_state 191 191 192 192 restore_host_regs 193 193 clrex @ Clear exclusive monitor
+3
arch/arm/kvm/mmio.c
··· 148 148 if (mmio.is_write) 149 149 memcpy(mmio.data, vcpu_reg(vcpu, rt), mmio.len); 150 150 151 + if (vgic_handle_mmio(vcpu, run, &mmio)) 152 + return 1; 153 + 151 154 kvm_prepare_mmio(run, &mmio); 152 155 return 0; 153 156 }
+153
arch/arm/kvm/vgic.c
··· 1 + /* 2 + * Copyright (C) 2012 ARM Ltd. 3 + * Author: Marc Zyngier <marc.zyngier@arm.com> 4 + * 5 + * This program is free software; you can redistribute it and/or modify 6 + * it under the terms of the GNU General Public License version 2 as 7 + * published by the Free Software Foundation. 8 + * 9 + * This program is distributed in the hope that it will be useful, 10 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 + * GNU General Public License for more details. 13 + * 14 + * You should have received a copy of the GNU General Public License 15 + * along with this program; if not, write to the Free Software 16 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17 + */ 18 + 19 + #include <linux/kvm.h> 20 + #include <linux/kvm_host.h> 21 + #include <linux/interrupt.h> 22 + #include <linux/io.h> 23 + #include <asm/kvm_emulate.h> 24 + 25 + #define ACCESS_READ_VALUE (1 << 0) 26 + #define ACCESS_READ_RAZ (0 << 0) 27 + #define ACCESS_READ_MASK(x) ((x) & (1 << 0)) 28 + #define ACCESS_WRITE_IGNORED (0 << 1) 29 + #define ACCESS_WRITE_SETBIT (1 << 1) 30 + #define ACCESS_WRITE_CLEARBIT (2 << 1) 31 + #define ACCESS_WRITE_VALUE (3 << 1) 32 + #define ACCESS_WRITE_MASK(x) ((x) & (3 << 1)) 33 + 34 + static u32 mmio_data_read(struct kvm_exit_mmio *mmio, u32 mask) 35 + { 36 + return *((u32 *)mmio->data) & mask; 37 + } 38 + 39 + static void mmio_data_write(struct kvm_exit_mmio *mmio, u32 mask, u32 value) 40 + { 41 + *((u32 *)mmio->data) = value & mask; 42 + } 43 + 44 + /** 45 + * vgic_reg_access - access vgic register 46 + * @mmio: pointer to the data describing the mmio access 47 + * @reg: pointer to the virtual backing of vgic distributor data 48 + * @offset: least significant 2 bits used for word offset 49 + * @mode: ACCESS_ mode (see defines above) 50 + * 51 + * Helper to make vgic register access easier using one of the access 52 + * modes defined for vgic register access 53 + * (read,raz,write-ignored,setbit,clearbit,write) 54 + */ 55 + static void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg, 56 + phys_addr_t offset, int mode) 57 + { 58 + int word_offset = (offset & 3) * 8; 59 + u32 mask = (1UL << (mmio->len * 8)) - 1; 60 + u32 regval; 61 + 62 + /* 63 + * Any alignment fault should have been delivered to the guest 64 + * directly (ARM ARM B3.12.7 "Prioritization of aborts"). 65 + */ 66 + 67 + if (reg) { 68 + regval = *reg; 69 + } else { 70 + BUG_ON(mode != (ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED)); 71 + regval = 0; 72 + } 73 + 74 + if (mmio->is_write) { 75 + u32 data = mmio_data_read(mmio, mask) << word_offset; 76 + switch (ACCESS_WRITE_MASK(mode)) { 77 + case ACCESS_WRITE_IGNORED: 78 + return; 79 + 80 + case ACCESS_WRITE_SETBIT: 81 + regval |= data; 82 + break; 83 + 84 + case ACCESS_WRITE_CLEARBIT: 85 + regval &= ~data; 86 + break; 87 + 88 + case ACCESS_WRITE_VALUE: 89 + regval = (regval & ~(mask << word_offset)) | data; 90 + break; 91 + } 92 + *reg = regval; 93 + } else { 94 + switch (ACCESS_READ_MASK(mode)) { 95 + case ACCESS_READ_RAZ: 96 + regval = 0; 97 + /* fall through */ 98 + 99 + case ACCESS_READ_VALUE: 100 + mmio_data_write(mmio, mask, regval >> word_offset); 101 + } 102 + } 103 + } 104 + 105 + /* 106 + * I would have liked to use the kvm_bus_io_*() API instead, but it 107 + * cannot cope with banked registers (only the VM pointer is passed 108 + * around, and we need the vcpu). One of these days, someone please 109 + * fix it! 110 + */ 111 + struct mmio_range { 112 + phys_addr_t base; 113 + unsigned long len; 114 + bool (*handle_mmio)(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio, 115 + phys_addr_t offset); 116 + }; 117 + 118 + static const struct mmio_range vgic_ranges[] = { 119 + {} 120 + }; 121 + 122 + static const 123 + struct mmio_range *find_matching_range(const struct mmio_range *ranges, 124 + struct kvm_exit_mmio *mmio, 125 + phys_addr_t base) 126 + { 127 + const struct mmio_range *r = ranges; 128 + phys_addr_t addr = mmio->phys_addr - base; 129 + 130 + while (r->len) { 131 + if (addr >= r->base && 132 + (addr + mmio->len) <= (r->base + r->len)) 133 + return r; 134 + r++; 135 + } 136 + 137 + return NULL; 138 + } 139 + 140 + /** 141 + * vgic_handle_mmio - handle an in-kernel MMIO access 142 + * @vcpu: pointer to the vcpu performing the access 143 + * @run: pointer to the kvm_run structure 144 + * @mmio: pointer to the data describing the access 145 + * 146 + * returns true if the MMIO access has been performed in kernel space, 147 + * and false if it needs to be emulated in user space. 148 + */ 149 + bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run, 150 + struct kvm_exit_mmio *mmio) 151 + { 152 + return KVM_EXIT_MMIO; 153 + }