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

Configure Feed

Select the types of activity you want to include in your feed.

RISC-V: Add initial skeletal KVM support

This patch adds initial skeletal KVM RISC-V support which has:
1. A simple implementation of arch specific VM functions
except kvm_vm_ioctl_get_dirty_log() which will implemeted
in-future as part of stage2 page loging.
2. Stubs of required arch specific VCPU functions except
kvm_arch_vcpu_ioctl_run() which is semi-complete and
extended by subsequent patches.
3. Stubs for required arch specific stage2 MMU functions.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Acked-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Paolo Bonzini <pbonzini@redhat.com>
Reviewed-by: Alexander Graf <graf@amazon.com>
Acked-by: Palmer Dabbelt <palmerdabbelt@google.com>

authored by

Anup Patel and committed by
Anup Patel
99cdc6c1 3f2401f4

+805
+1
arch/riscv/Kconfig
··· 562 562 563 563 endmenu 564 564 565 + source "arch/riscv/kvm/Kconfig" 565 566 source "drivers/firmware/Kconfig"
+1
arch/riscv/Makefile
··· 100 100 head-y := arch/riscv/kernel/head.o 101 101 102 102 core-$(CONFIG_RISCV_ERRATA_ALTERNATIVE) += arch/riscv/errata/ 103 + core-$(CONFIG_KVM) += arch/riscv/kvm/ 103 104 104 105 libs-y += arch/riscv/lib/ 105 106 libs-$(CONFIG_EFI_STUB) += $(objtree)/drivers/firmware/efi/libstub/lib.a
+84
arch/riscv/include/asm/kvm_host.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2019 Western Digital Corporation or its affiliates. 4 + * 5 + * Authors: 6 + * Anup Patel <anup.patel@wdc.com> 7 + */ 8 + 9 + #ifndef __RISCV_KVM_HOST_H__ 10 + #define __RISCV_KVM_HOST_H__ 11 + 12 + #include <linux/types.h> 13 + #include <linux/kvm.h> 14 + #include <linux/kvm_types.h> 15 + 16 + #ifdef CONFIG_64BIT 17 + #define KVM_MAX_VCPUS (1U << 16) 18 + #else 19 + #define KVM_MAX_VCPUS (1U << 9) 20 + #endif 21 + 22 + #define KVM_HALT_POLL_NS_DEFAULT 500000 23 + 24 + #define KVM_VCPU_MAX_FEATURES 0 25 + 26 + #define KVM_REQ_SLEEP \ 27 + KVM_ARCH_REQ_FLAGS(0, KVM_REQUEST_WAIT | KVM_REQUEST_NO_WAKEUP) 28 + #define KVM_REQ_VCPU_RESET KVM_ARCH_REQ(1) 29 + 30 + struct kvm_vm_stat { 31 + struct kvm_vm_stat_generic generic; 32 + }; 33 + 34 + struct kvm_vcpu_stat { 35 + struct kvm_vcpu_stat_generic generic; 36 + u64 ecall_exit_stat; 37 + u64 wfi_exit_stat; 38 + u64 mmio_exit_user; 39 + u64 mmio_exit_kernel; 40 + u64 exits; 41 + }; 42 + 43 + struct kvm_arch_memory_slot { 44 + }; 45 + 46 + struct kvm_arch { 47 + /* stage2 page table */ 48 + pgd_t *pgd; 49 + phys_addr_t pgd_phys; 50 + }; 51 + 52 + struct kvm_cpu_trap { 53 + unsigned long sepc; 54 + unsigned long scause; 55 + unsigned long stval; 56 + unsigned long htval; 57 + unsigned long htinst; 58 + }; 59 + 60 + struct kvm_vcpu_arch { 61 + /* Don't run the VCPU (blocked) */ 62 + bool pause; 63 + 64 + /* SRCU lock index for in-kernel run loop */ 65 + int srcu_idx; 66 + }; 67 + 68 + static inline void kvm_arch_hardware_unsetup(void) {} 69 + static inline void kvm_arch_sync_events(struct kvm *kvm) {} 70 + static inline void kvm_arch_sched_in(struct kvm_vcpu *vcpu, int cpu) {} 71 + static inline void kvm_arch_vcpu_block_finish(struct kvm_vcpu *vcpu) {} 72 + 73 + void kvm_riscv_stage2_flush_cache(struct kvm_vcpu *vcpu); 74 + int kvm_riscv_stage2_alloc_pgd(struct kvm *kvm); 75 + void kvm_riscv_stage2_free_pgd(struct kvm *kvm); 76 + void kvm_riscv_stage2_update_hgatp(struct kvm_vcpu *vcpu); 77 + 78 + int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run); 79 + int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, 80 + struct kvm_cpu_trap *trap); 81 + 82 + static inline void __kvm_riscv_switch_to(struct kvm_vcpu_arch *vcpu_arch) {} 83 + 84 + #endif /* __RISCV_KVM_HOST_H__ */
+7
arch/riscv/include/asm/kvm_types.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _ASM_RISCV_KVM_TYPES_H 3 + #define _ASM_RISCV_KVM_TYPES_H 4 + 5 + #define KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE 40 6 + 7 + #endif /* _ASM_RISCV_KVM_TYPES_H */
+47
arch/riscv/include/uapi/asm/kvm.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 + /* 3 + * Copyright (C) 2019 Western Digital Corporation or its affiliates. 4 + * 5 + * Authors: 6 + * Anup Patel <anup.patel@wdc.com> 7 + */ 8 + 9 + #ifndef __LINUX_KVM_RISCV_H 10 + #define __LINUX_KVM_RISCV_H 11 + 12 + #ifndef __ASSEMBLY__ 13 + 14 + #include <linux/types.h> 15 + #include <asm/ptrace.h> 16 + 17 + #define __KVM_HAVE_READONLY_MEM 18 + 19 + #define KVM_COALESCED_MMIO_PAGE_OFFSET 1 20 + 21 + /* for KVM_GET_REGS and KVM_SET_REGS */ 22 + struct kvm_regs { 23 + }; 24 + 25 + /* for KVM_GET_FPU and KVM_SET_FPU */ 26 + struct kvm_fpu { 27 + }; 28 + 29 + /* KVM Debug exit structure */ 30 + struct kvm_debug_exit_arch { 31 + }; 32 + 33 + /* for KVM_SET_GUEST_DEBUG */ 34 + struct kvm_guest_debug_arch { 35 + }; 36 + 37 + /* definition of registers in kvm_run */ 38 + struct kvm_sync_regs { 39 + }; 40 + 41 + /* dummy definition */ 42 + struct kvm_sregs { 43 + }; 44 + 45 + #endif 46 + 47 + #endif /* __LINUX_KVM_RISCV_H */
+33
arch/riscv/kvm/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # KVM configuration 4 + # 5 + 6 + source "virt/kvm/Kconfig" 7 + 8 + menuconfig VIRTUALIZATION 9 + bool "Virtualization" 10 + help 11 + Say Y here to get to see options for using your Linux host to run 12 + other operating systems inside virtual machines (guests). 13 + This option alone does not add any kernel code. 14 + 15 + If you say N, all options in this submenu will be skipped and 16 + disabled. 17 + 18 + if VIRTUALIZATION 19 + 20 + config KVM 21 + tristate "Kernel-based Virtual Machine (KVM) support (EXPERIMENTAL)" 22 + depends on RISCV_SBI && MMU 23 + select PREEMPT_NOTIFIERS 24 + select ANON_INODES 25 + select KVM_MMIO 26 + select HAVE_KVM_VCPU_ASYNC_IOCTL 27 + select SRCU 28 + help 29 + Support hosting virtualized guest machines. 30 + 31 + If unsure, say N. 32 + 33 + endif # VIRTUALIZATION
+13
arch/riscv/kvm/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # 3 + # Makefile for RISC-V KVM support 4 + # 5 + 6 + ccflags-y += -I $(srctree)/$(src) 7 + 8 + KVM := ../../../virt/kvm 9 + 10 + obj-$(CONFIG_KVM) += kvm.o 11 + 12 + kvm-y += $(KVM)/kvm_main.o $(KVM)/coalesced_mmio.o $(KVM)/binary_stats.o \ 13 + main.o vm.o mmu.o vcpu.o vcpu_exit.o
+95
arch/riscv/kvm/main.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2019 Western Digital Corporation or its affiliates. 4 + * 5 + * Authors: 6 + * Anup Patel <anup.patel@wdc.com> 7 + */ 8 + 9 + #include <linux/errno.h> 10 + #include <linux/err.h> 11 + #include <linux/module.h> 12 + #include <linux/kvm_host.h> 13 + #include <asm/csr.h> 14 + #include <asm/hwcap.h> 15 + #include <asm/sbi.h> 16 + 17 + long kvm_arch_dev_ioctl(struct file *filp, 18 + unsigned int ioctl, unsigned long arg) 19 + { 20 + return -EINVAL; 21 + } 22 + 23 + int kvm_arch_check_processor_compat(void *opaque) 24 + { 25 + return 0; 26 + } 27 + 28 + int kvm_arch_hardware_setup(void *opaque) 29 + { 30 + return 0; 31 + } 32 + 33 + int kvm_arch_hardware_enable(void) 34 + { 35 + unsigned long hideleg, hedeleg; 36 + 37 + hedeleg = 0; 38 + hedeleg |= (1UL << EXC_INST_MISALIGNED); 39 + hedeleg |= (1UL << EXC_BREAKPOINT); 40 + hedeleg |= (1UL << EXC_SYSCALL); 41 + hedeleg |= (1UL << EXC_INST_PAGE_FAULT); 42 + hedeleg |= (1UL << EXC_LOAD_PAGE_FAULT); 43 + hedeleg |= (1UL << EXC_STORE_PAGE_FAULT); 44 + csr_write(CSR_HEDELEG, hedeleg); 45 + 46 + hideleg = 0; 47 + hideleg |= (1UL << IRQ_VS_SOFT); 48 + hideleg |= (1UL << IRQ_VS_TIMER); 49 + hideleg |= (1UL << IRQ_VS_EXT); 50 + csr_write(CSR_HIDELEG, hideleg); 51 + 52 + csr_write(CSR_HCOUNTEREN, -1UL); 53 + 54 + csr_write(CSR_HVIP, 0); 55 + 56 + return 0; 57 + } 58 + 59 + void kvm_arch_hardware_disable(void) 60 + { 61 + csr_write(CSR_HEDELEG, 0); 62 + csr_write(CSR_HIDELEG, 0); 63 + } 64 + 65 + int kvm_arch_init(void *opaque) 66 + { 67 + if (!riscv_isa_extension_available(NULL, h)) { 68 + kvm_info("hypervisor extension not available\n"); 69 + return -ENODEV; 70 + } 71 + 72 + if (sbi_spec_is_0_1()) { 73 + kvm_info("require SBI v0.2 or higher\n"); 74 + return -ENODEV; 75 + } 76 + 77 + if (sbi_probe_extension(SBI_EXT_RFENCE) <= 0) { 78 + kvm_info("require SBI RFENCE extension\n"); 79 + return -ENODEV; 80 + } 81 + 82 + kvm_info("hypervisor extension available\n"); 83 + 84 + return 0; 85 + } 86 + 87 + void kvm_arch_exit(void) 88 + { 89 + } 90 + 91 + static int riscv_kvm_init(void) 92 + { 93 + return kvm_init(NULL, sizeof(struct kvm_vcpu), 0, THIS_MODULE); 94 + } 95 + module_init(riscv_kvm_init);
+80
arch/riscv/kvm/mmu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2019 Western Digital Corporation or its affiliates. 4 + * 5 + * Authors: 6 + * Anup Patel <anup.patel@wdc.com> 7 + */ 8 + 9 + #include <linux/bitops.h> 10 + #include <linux/errno.h> 11 + #include <linux/err.h> 12 + #include <linux/hugetlb.h> 13 + #include <linux/module.h> 14 + #include <linux/uaccess.h> 15 + #include <linux/vmalloc.h> 16 + #include <linux/kvm_host.h> 17 + #include <linux/sched/signal.h> 18 + #include <asm/page.h> 19 + #include <asm/pgtable.h> 20 + 21 + void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot) 22 + { 23 + } 24 + 25 + void kvm_arch_free_memslot(struct kvm *kvm, struct kvm_memory_slot *free) 26 + { 27 + } 28 + 29 + void kvm_arch_memslots_updated(struct kvm *kvm, u64 gen) 30 + { 31 + } 32 + 33 + void kvm_arch_flush_shadow_all(struct kvm *kvm) 34 + { 35 + /* TODO: */ 36 + } 37 + 38 + void kvm_arch_flush_shadow_memslot(struct kvm *kvm, 39 + struct kvm_memory_slot *slot) 40 + { 41 + } 42 + 43 + void kvm_arch_commit_memory_region(struct kvm *kvm, 44 + const struct kvm_userspace_memory_region *mem, 45 + struct kvm_memory_slot *old, 46 + const struct kvm_memory_slot *new, 47 + enum kvm_mr_change change) 48 + { 49 + /* TODO: */ 50 + } 51 + 52 + int kvm_arch_prepare_memory_region(struct kvm *kvm, 53 + struct kvm_memory_slot *memslot, 54 + const struct kvm_userspace_memory_region *mem, 55 + enum kvm_mr_change change) 56 + { 57 + /* TODO: */ 58 + return 0; 59 + } 60 + 61 + void kvm_riscv_stage2_flush_cache(struct kvm_vcpu *vcpu) 62 + { 63 + /* TODO: */ 64 + } 65 + 66 + int kvm_riscv_stage2_alloc_pgd(struct kvm *kvm) 67 + { 68 + /* TODO: */ 69 + return 0; 70 + } 71 + 72 + void kvm_riscv_stage2_free_pgd(struct kvm *kvm) 73 + { 74 + /* TODO: */ 75 + } 76 + 77 + void kvm_riscv_stage2_update_hgatp(struct kvm_vcpu *vcpu) 78 + { 79 + /* TODO: */ 80 + }
+314
arch/riscv/kvm/vcpu.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2019 Western Digital Corporation or its affiliates. 4 + * 5 + * Authors: 6 + * Anup Patel <anup.patel@wdc.com> 7 + */ 8 + 9 + #include <linux/bitops.h> 10 + #include <linux/errno.h> 11 + #include <linux/err.h> 12 + #include <linux/kdebug.h> 13 + #include <linux/module.h> 14 + #include <linux/uaccess.h> 15 + #include <linux/vmalloc.h> 16 + #include <linux/sched/signal.h> 17 + #include <linux/fs.h> 18 + #include <linux/kvm_host.h> 19 + #include <asm/csr.h> 20 + #include <asm/delay.h> 21 + #include <asm/hwcap.h> 22 + 23 + const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = { 24 + KVM_GENERIC_VCPU_STATS(), 25 + STATS_DESC_COUNTER(VCPU, ecall_exit_stat), 26 + STATS_DESC_COUNTER(VCPU, wfi_exit_stat), 27 + STATS_DESC_COUNTER(VCPU, mmio_exit_user), 28 + STATS_DESC_COUNTER(VCPU, mmio_exit_kernel), 29 + STATS_DESC_COUNTER(VCPU, exits) 30 + }; 31 + 32 + const struct kvm_stats_header kvm_vcpu_stats_header = { 33 + .name_size = KVM_STATS_NAME_SIZE, 34 + .num_desc = ARRAY_SIZE(kvm_vcpu_stats_desc), 35 + .id_offset = sizeof(struct kvm_stats_header), 36 + .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE, 37 + .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE + 38 + sizeof(kvm_vcpu_stats_desc), 39 + }; 40 + 41 + int kvm_arch_vcpu_precreate(struct kvm *kvm, unsigned int id) 42 + { 43 + return 0; 44 + } 45 + 46 + int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) 47 + { 48 + /* TODO: */ 49 + return 0; 50 + } 51 + 52 + void kvm_arch_vcpu_postcreate(struct kvm_vcpu *vcpu) 53 + { 54 + } 55 + 56 + int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu) 57 + { 58 + /* TODO: */ 59 + return 0; 60 + } 61 + 62 + void kvm_arch_vcpu_destroy(struct kvm_vcpu *vcpu) 63 + { 64 + /* TODO: */ 65 + } 66 + 67 + int kvm_cpu_has_pending_timer(struct kvm_vcpu *vcpu) 68 + { 69 + /* TODO: */ 70 + return 0; 71 + } 72 + 73 + void kvm_arch_vcpu_blocking(struct kvm_vcpu *vcpu) 74 + { 75 + } 76 + 77 + void kvm_arch_vcpu_unblocking(struct kvm_vcpu *vcpu) 78 + { 79 + } 80 + 81 + int kvm_arch_vcpu_runnable(struct kvm_vcpu *vcpu) 82 + { 83 + /* TODO: */ 84 + return 0; 85 + } 86 + 87 + int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu) 88 + { 89 + /* TODO: */ 90 + return 0; 91 + } 92 + 93 + bool kvm_arch_vcpu_in_kernel(struct kvm_vcpu *vcpu) 94 + { 95 + /* TODO: */ 96 + return false; 97 + } 98 + 99 + vm_fault_t kvm_arch_vcpu_fault(struct kvm_vcpu *vcpu, struct vm_fault *vmf) 100 + { 101 + return VM_FAULT_SIGBUS; 102 + } 103 + 104 + long kvm_arch_vcpu_async_ioctl(struct file *filp, 105 + unsigned int ioctl, unsigned long arg) 106 + { 107 + /* TODO; */ 108 + return -ENOIOCTLCMD; 109 + } 110 + 111 + long kvm_arch_vcpu_ioctl(struct file *filp, 112 + unsigned int ioctl, unsigned long arg) 113 + { 114 + /* TODO: */ 115 + return -EINVAL; 116 + } 117 + 118 + int kvm_arch_vcpu_ioctl_get_sregs(struct kvm_vcpu *vcpu, 119 + struct kvm_sregs *sregs) 120 + { 121 + return -EINVAL; 122 + } 123 + 124 + int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu, 125 + struct kvm_sregs *sregs) 126 + { 127 + return -EINVAL; 128 + } 129 + 130 + int kvm_arch_vcpu_ioctl_get_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) 131 + { 132 + return -EINVAL; 133 + } 134 + 135 + int kvm_arch_vcpu_ioctl_set_fpu(struct kvm_vcpu *vcpu, struct kvm_fpu *fpu) 136 + { 137 + return -EINVAL; 138 + } 139 + 140 + int kvm_arch_vcpu_ioctl_translate(struct kvm_vcpu *vcpu, 141 + struct kvm_translation *tr) 142 + { 143 + return -EINVAL; 144 + } 145 + 146 + int kvm_arch_vcpu_ioctl_get_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) 147 + { 148 + return -EINVAL; 149 + } 150 + 151 + int kvm_arch_vcpu_ioctl_set_regs(struct kvm_vcpu *vcpu, struct kvm_regs *regs) 152 + { 153 + return -EINVAL; 154 + } 155 + 156 + int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu, 157 + struct kvm_mp_state *mp_state) 158 + { 159 + /* TODO: */ 160 + return 0; 161 + } 162 + 163 + int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, 164 + struct kvm_mp_state *mp_state) 165 + { 166 + /* TODO: */ 167 + return 0; 168 + } 169 + 170 + int kvm_arch_vcpu_ioctl_set_guest_debug(struct kvm_vcpu *vcpu, 171 + struct kvm_guest_debug *dbg) 172 + { 173 + /* TODO; To be implemented later. */ 174 + return -EINVAL; 175 + } 176 + 177 + void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu) 178 + { 179 + /* TODO: */ 180 + 181 + kvm_riscv_stage2_update_hgatp(vcpu); 182 + } 183 + 184 + void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) 185 + { 186 + /* TODO: */ 187 + } 188 + 189 + static void kvm_riscv_check_vcpu_requests(struct kvm_vcpu *vcpu) 190 + { 191 + /* TODO: */ 192 + } 193 + 194 + int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu) 195 + { 196 + int ret; 197 + struct kvm_cpu_trap trap; 198 + struct kvm_run *run = vcpu->run; 199 + 200 + vcpu->arch.srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 201 + 202 + /* Process MMIO value returned from user-space */ 203 + if (run->exit_reason == KVM_EXIT_MMIO) { 204 + ret = kvm_riscv_vcpu_mmio_return(vcpu, vcpu->run); 205 + if (ret) { 206 + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx); 207 + return ret; 208 + } 209 + } 210 + 211 + if (run->immediate_exit) { 212 + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx); 213 + return -EINTR; 214 + } 215 + 216 + vcpu_load(vcpu); 217 + 218 + kvm_sigset_activate(vcpu); 219 + 220 + ret = 1; 221 + run->exit_reason = KVM_EXIT_UNKNOWN; 222 + while (ret > 0) { 223 + /* Check conditions before entering the guest */ 224 + cond_resched(); 225 + 226 + kvm_riscv_check_vcpu_requests(vcpu); 227 + 228 + preempt_disable(); 229 + 230 + local_irq_disable(); 231 + 232 + /* 233 + * Exit if we have a signal pending so that we can deliver 234 + * the signal to user space. 235 + */ 236 + if (signal_pending(current)) { 237 + ret = -EINTR; 238 + run->exit_reason = KVM_EXIT_INTR; 239 + } 240 + 241 + /* 242 + * Ensure we set mode to IN_GUEST_MODE after we disable 243 + * interrupts and before the final VCPU requests check. 244 + * See the comment in kvm_vcpu_exiting_guest_mode() and 245 + * Documentation/virtual/kvm/vcpu-requests.rst 246 + */ 247 + vcpu->mode = IN_GUEST_MODE; 248 + 249 + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx); 250 + smp_mb__after_srcu_read_unlock(); 251 + 252 + if (ret <= 0 || 253 + kvm_request_pending(vcpu)) { 254 + vcpu->mode = OUTSIDE_GUEST_MODE; 255 + local_irq_enable(); 256 + preempt_enable(); 257 + vcpu->arch.srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 258 + continue; 259 + } 260 + 261 + guest_enter_irqoff(); 262 + 263 + __kvm_riscv_switch_to(&vcpu->arch); 264 + 265 + vcpu->mode = OUTSIDE_GUEST_MODE; 266 + vcpu->stat.exits++; 267 + 268 + /* 269 + * Save SCAUSE, STVAL, HTVAL, and HTINST because we might 270 + * get an interrupt between __kvm_riscv_switch_to() and 271 + * local_irq_enable() which can potentially change CSRs. 272 + */ 273 + trap.sepc = 0; 274 + trap.scause = csr_read(CSR_SCAUSE); 275 + trap.stval = csr_read(CSR_STVAL); 276 + trap.htval = csr_read(CSR_HTVAL); 277 + trap.htinst = csr_read(CSR_HTINST); 278 + 279 + /* 280 + * We may have taken a host interrupt in VS/VU-mode (i.e. 281 + * while executing the guest). This interrupt is still 282 + * pending, as we haven't serviced it yet! 283 + * 284 + * We're now back in HS-mode with interrupts disabled 285 + * so enabling the interrupts now will have the effect 286 + * of taking the interrupt again, in HS-mode this time. 287 + */ 288 + local_irq_enable(); 289 + 290 + /* 291 + * We do local_irq_enable() before calling guest_exit() so 292 + * that if a timer interrupt hits while running the guest 293 + * we account that tick as being spent in the guest. We 294 + * enable preemption after calling guest_exit() so that if 295 + * we get preempted we make sure ticks after that is not 296 + * counted as guest time. 297 + */ 298 + guest_exit(); 299 + 300 + preempt_enable(); 301 + 302 + vcpu->arch.srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); 303 + 304 + ret = kvm_riscv_vcpu_exit(vcpu, run, &trap); 305 + } 306 + 307 + kvm_sigset_deactivate(vcpu); 308 + 309 + vcpu_put(vcpu); 310 + 311 + srcu_read_unlock(&vcpu->kvm->srcu, vcpu->arch.srcu_idx); 312 + 313 + return ret; 314 + }
+35
arch/riscv/kvm/vcpu_exit.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2019 Western Digital Corporation or its affiliates. 4 + * 5 + * Authors: 6 + * Anup Patel <anup.patel@wdc.com> 7 + */ 8 + 9 + #include <linux/errno.h> 10 + #include <linux/err.h> 11 + #include <linux/kvm_host.h> 12 + 13 + /** 14 + * kvm_riscv_vcpu_mmio_return -- Handle MMIO loads after user space emulation 15 + * or in-kernel IO emulation 16 + * 17 + * @vcpu: The VCPU pointer 18 + * @run: The VCPU run struct containing the mmio data 19 + */ 20 + int kvm_riscv_vcpu_mmio_return(struct kvm_vcpu *vcpu, struct kvm_run *run) 21 + { 22 + /* TODO: */ 23 + return 0; 24 + } 25 + 26 + /* 27 + * Return > 0 to return to guest, < 0 on error, 0 (and set exit_reason) on 28 + * proper exit to userspace. 29 + */ 30 + int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, 31 + struct kvm_cpu_trap *trap) 32 + { 33 + /* TODO: */ 34 + return 0; 35 + }
+95
arch/riscv/kvm/vm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2019 Western Digital Corporation or its affiliates. 4 + * 5 + * Authors: 6 + * Anup Patel <anup.patel@wdc.com> 7 + */ 8 + 9 + #include <linux/errno.h> 10 + #include <linux/err.h> 11 + #include <linux/module.h> 12 + #include <linux/uaccess.h> 13 + #include <linux/kvm_host.h> 14 + 15 + const struct _kvm_stats_desc kvm_vm_stats_desc[] = { 16 + KVM_GENERIC_VM_STATS() 17 + }; 18 + static_assert(ARRAY_SIZE(kvm_vm_stats_desc) == 19 + sizeof(struct kvm_vm_stat) / sizeof(u64)); 20 + 21 + const struct kvm_stats_header kvm_vm_stats_header = { 22 + .name_size = KVM_STATS_NAME_SIZE, 23 + .num_desc = ARRAY_SIZE(kvm_vm_stats_desc), 24 + .id_offset = sizeof(struct kvm_stats_header), 25 + .desc_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE, 26 + .data_offset = sizeof(struct kvm_stats_header) + KVM_STATS_NAME_SIZE + 27 + sizeof(kvm_vm_stats_desc), 28 + }; 29 + 30 + int kvm_vm_ioctl_get_dirty_log(struct kvm *kvm, struct kvm_dirty_log *log) 31 + { 32 + /* TODO: To be added later. */ 33 + return -EOPNOTSUPP; 34 + } 35 + 36 + int kvm_arch_init_vm(struct kvm *kvm, unsigned long type) 37 + { 38 + int r; 39 + 40 + r = kvm_riscv_stage2_alloc_pgd(kvm); 41 + if (r) 42 + return r; 43 + 44 + return 0; 45 + } 46 + 47 + void kvm_arch_destroy_vm(struct kvm *kvm) 48 + { 49 + int i; 50 + 51 + for (i = 0; i < KVM_MAX_VCPUS; ++i) { 52 + if (kvm->vcpus[i]) { 53 + kvm_vcpu_destroy(kvm->vcpus[i]); 54 + kvm->vcpus[i] = NULL; 55 + } 56 + } 57 + atomic_set(&kvm->online_vcpus, 0); 58 + } 59 + 60 + int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) 61 + { 62 + int r; 63 + 64 + switch (ext) { 65 + case KVM_CAP_DEVICE_CTRL: 66 + case KVM_CAP_USER_MEMORY: 67 + case KVM_CAP_DESTROY_MEMORY_REGION_WORKS: 68 + case KVM_CAP_ONE_REG: 69 + case KVM_CAP_READONLY_MEM: 70 + case KVM_CAP_MP_STATE: 71 + case KVM_CAP_IMMEDIATE_EXIT: 72 + r = 1; 73 + break; 74 + case KVM_CAP_NR_VCPUS: 75 + r = num_online_cpus(); 76 + break; 77 + case KVM_CAP_MAX_VCPUS: 78 + r = KVM_MAX_VCPUS; 79 + break; 80 + case KVM_CAP_NR_MEMSLOTS: 81 + r = KVM_USER_MEM_SLOTS; 82 + break; 83 + default: 84 + r = 0; 85 + break; 86 + } 87 + 88 + return r; 89 + } 90 + 91 + long kvm_arch_vm_ioctl(struct file *filp, 92 + unsigned int ioctl, unsigned long arg) 93 + { 94 + return -EINVAL; 95 + }