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

RISC-V: KVM: Factor-out FP virtualization into separate sources

The timer and SBI virtualization is already in separate sources.
In future, we will have vector and AIA virtualization also added
as separate sources.

To align with above described modularity, we factor-out FP
virtualization into separate sources.

Signed-off-by: Anup Patel <anup.patel@wdc.com>
Message-Id: <20211026170136.2147619-3-anup.patel@wdc.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Anup Patel and committed by
Paolo Bonzini
0a86512d 4e338684

+228 -176
+1 -4
arch/riscv/include/asm/kvm_host.h
··· 12 12 #include <linux/types.h> 13 13 #include <linux/kvm.h> 14 14 #include <linux/kvm_types.h> 15 + #include <asm/kvm_vcpu_fp.h> 15 16 #include <asm/kvm_vcpu_timer.h> 16 17 17 18 #ifdef CONFIG_64BIT ··· 248 247 struct kvm_cpu_trap *trap); 249 248 250 249 void __kvm_riscv_switch_to(struct kvm_vcpu_arch *vcpu_arch); 251 - void __kvm_riscv_fp_f_save(struct kvm_cpu_context *context); 252 - void __kvm_riscv_fp_f_restore(struct kvm_cpu_context *context); 253 - void __kvm_riscv_fp_d_save(struct kvm_cpu_context *context); 254 - void __kvm_riscv_fp_d_restore(struct kvm_cpu_context *context); 255 250 256 251 int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq); 257 252 int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq);
+59
arch/riscv/include/asm/kvm_vcpu_fp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (C) 2021 Western Digital Corporation or its affiliates. 4 + * 5 + * Authors: 6 + * Atish Patra <atish.patra@wdc.com> 7 + * Anup Patel <anup.patel@wdc.com> 8 + */ 9 + 10 + #ifndef __KVM_VCPU_RISCV_FP_H 11 + #define __KVM_VCPU_RISCV_FP_H 12 + 13 + #include <linux/types.h> 14 + 15 + struct kvm_cpu_context; 16 + 17 + #ifdef CONFIG_FPU 18 + void __kvm_riscv_fp_f_save(struct kvm_cpu_context *context); 19 + void __kvm_riscv_fp_f_restore(struct kvm_cpu_context *context); 20 + void __kvm_riscv_fp_d_save(struct kvm_cpu_context *context); 21 + void __kvm_riscv_fp_d_restore(struct kvm_cpu_context *context); 22 + 23 + void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu); 24 + void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx, 25 + unsigned long isa); 26 + void kvm_riscv_vcpu_guest_fp_restore(struct kvm_cpu_context *cntx, 27 + unsigned long isa); 28 + void kvm_riscv_vcpu_host_fp_save(struct kvm_cpu_context *cntx); 29 + void kvm_riscv_vcpu_host_fp_restore(struct kvm_cpu_context *cntx); 30 + #else 31 + static inline void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu) 32 + { 33 + } 34 + static inline void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx, 35 + unsigned long isa) 36 + { 37 + } 38 + static inline void kvm_riscv_vcpu_guest_fp_restore( 39 + struct kvm_cpu_context *cntx, 40 + unsigned long isa) 41 + { 42 + } 43 + static inline void kvm_riscv_vcpu_host_fp_save(struct kvm_cpu_context *cntx) 44 + { 45 + } 46 + static inline void kvm_riscv_vcpu_host_fp_restore( 47 + struct kvm_cpu_context *cntx) 48 + { 49 + } 50 + #endif 51 + 52 + int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu, 53 + const struct kvm_one_reg *reg, 54 + unsigned long rtype); 55 + int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu, 56 + const struct kvm_one_reg *reg, 57 + unsigned long rtype); 58 + 59 + #endif
+1
arch/riscv/kvm/Makefile
··· 20 20 kvm-y += mmu.o 21 21 kvm-y += vcpu.o 22 22 kvm-y += vcpu_exit.o 23 + kvm-y += vcpu_fp.o 23 24 kvm-y += vcpu_switch.o 24 25 kvm-y += vcpu_sbi.o 25 26 kvm-y += vcpu_timer.o
-172
arch/riscv/kvm/vcpu.c
··· 38 38 sizeof(kvm_vcpu_stats_desc), 39 39 }; 40 40 41 - #ifdef CONFIG_FPU 42 - static void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu) 43 - { 44 - unsigned long isa = vcpu->arch.isa; 45 - struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; 46 - 47 - cntx->sstatus &= ~SR_FS; 48 - if (riscv_isa_extension_available(&isa, f) || 49 - riscv_isa_extension_available(&isa, d)) 50 - cntx->sstatus |= SR_FS_INITIAL; 51 - else 52 - cntx->sstatus |= SR_FS_OFF; 53 - } 54 - 55 - static void kvm_riscv_vcpu_fp_clean(struct kvm_cpu_context *cntx) 56 - { 57 - cntx->sstatus &= ~SR_FS; 58 - cntx->sstatus |= SR_FS_CLEAN; 59 - } 60 - 61 - static void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx, 62 - unsigned long isa) 63 - { 64 - if ((cntx->sstatus & SR_FS) == SR_FS_DIRTY) { 65 - if (riscv_isa_extension_available(&isa, d)) 66 - __kvm_riscv_fp_d_save(cntx); 67 - else if (riscv_isa_extension_available(&isa, f)) 68 - __kvm_riscv_fp_f_save(cntx); 69 - kvm_riscv_vcpu_fp_clean(cntx); 70 - } 71 - } 72 - 73 - static void kvm_riscv_vcpu_guest_fp_restore(struct kvm_cpu_context *cntx, 74 - unsigned long isa) 75 - { 76 - if ((cntx->sstatus & SR_FS) != SR_FS_OFF) { 77 - if (riscv_isa_extension_available(&isa, d)) 78 - __kvm_riscv_fp_d_restore(cntx); 79 - else if (riscv_isa_extension_available(&isa, f)) 80 - __kvm_riscv_fp_f_restore(cntx); 81 - kvm_riscv_vcpu_fp_clean(cntx); 82 - } 83 - } 84 - 85 - static void kvm_riscv_vcpu_host_fp_save(struct kvm_cpu_context *cntx) 86 - { 87 - /* No need to check host sstatus as it can be modified outside */ 88 - if (riscv_isa_extension_available(NULL, d)) 89 - __kvm_riscv_fp_d_save(cntx); 90 - else if (riscv_isa_extension_available(NULL, f)) 91 - __kvm_riscv_fp_f_save(cntx); 92 - } 93 - 94 - static void kvm_riscv_vcpu_host_fp_restore(struct kvm_cpu_context *cntx) 95 - { 96 - if (riscv_isa_extension_available(NULL, d)) 97 - __kvm_riscv_fp_d_restore(cntx); 98 - else if (riscv_isa_extension_available(NULL, f)) 99 - __kvm_riscv_fp_f_restore(cntx); 100 - } 101 - #else 102 - static void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu) 103 - { 104 - } 105 - static void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx, 106 - unsigned long isa) 107 - { 108 - } 109 - static void kvm_riscv_vcpu_guest_fp_restore(struct kvm_cpu_context *cntx, 110 - unsigned long isa) 111 - { 112 - } 113 - static void kvm_riscv_vcpu_host_fp_save(struct kvm_cpu_context *cntx) 114 - { 115 - } 116 - static void kvm_riscv_vcpu_host_fp_restore(struct kvm_cpu_context *cntx) 117 - { 118 - } 119 - #endif 120 - 121 41 #define KVM_RISCV_ISA_ALLOWED (riscv_isa_extension_mask(a) | \ 122 42 riscv_isa_extension_mask(c) | \ 123 43 riscv_isa_extension_mask(d) | \ ··· 330 410 331 411 if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) 332 412 WRITE_ONCE(vcpu->arch.irqs_pending_mask, 0); 333 - 334 - return 0; 335 - } 336 - 337 - static int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu, 338 - const struct kvm_one_reg *reg, 339 - unsigned long rtype) 340 - { 341 - struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; 342 - unsigned long isa = vcpu->arch.isa; 343 - unsigned long __user *uaddr = 344 - (unsigned long __user *)(unsigned long)reg->addr; 345 - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | 346 - KVM_REG_SIZE_MASK | 347 - rtype); 348 - void *reg_val; 349 - 350 - if ((rtype == KVM_REG_RISCV_FP_F) && 351 - riscv_isa_extension_available(&isa, f)) { 352 - if (KVM_REG_SIZE(reg->id) != sizeof(u32)) 353 - return -EINVAL; 354 - if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr)) 355 - reg_val = &cntx->fp.f.fcsr; 356 - else if ((KVM_REG_RISCV_FP_F_REG(f[0]) <= reg_num) && 357 - reg_num <= KVM_REG_RISCV_FP_F_REG(f[31])) 358 - reg_val = &cntx->fp.f.f[reg_num]; 359 - else 360 - return -EINVAL; 361 - } else if ((rtype == KVM_REG_RISCV_FP_D) && 362 - riscv_isa_extension_available(&isa, d)) { 363 - if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) { 364 - if (KVM_REG_SIZE(reg->id) != sizeof(u32)) 365 - return -EINVAL; 366 - reg_val = &cntx->fp.d.fcsr; 367 - } else if ((KVM_REG_RISCV_FP_D_REG(f[0]) <= reg_num) && 368 - reg_num <= KVM_REG_RISCV_FP_D_REG(f[31])) { 369 - if (KVM_REG_SIZE(reg->id) != sizeof(u64)) 370 - return -EINVAL; 371 - reg_val = &cntx->fp.d.f[reg_num]; 372 - } else 373 - return -EINVAL; 374 - } else 375 - return -EINVAL; 376 - 377 - if (copy_to_user(uaddr, reg_val, KVM_REG_SIZE(reg->id))) 378 - return -EFAULT; 379 - 380 - return 0; 381 - } 382 - 383 - static int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu, 384 - const struct kvm_one_reg *reg, 385 - unsigned long rtype) 386 - { 387 - struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; 388 - unsigned long isa = vcpu->arch.isa; 389 - unsigned long __user *uaddr = 390 - (unsigned long __user *)(unsigned long)reg->addr; 391 - unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | 392 - KVM_REG_SIZE_MASK | 393 - rtype); 394 - void *reg_val; 395 - 396 - if ((rtype == KVM_REG_RISCV_FP_F) && 397 - riscv_isa_extension_available(&isa, f)) { 398 - if (KVM_REG_SIZE(reg->id) != sizeof(u32)) 399 - return -EINVAL; 400 - if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr)) 401 - reg_val = &cntx->fp.f.fcsr; 402 - else if ((KVM_REG_RISCV_FP_F_REG(f[0]) <= reg_num) && 403 - reg_num <= KVM_REG_RISCV_FP_F_REG(f[31])) 404 - reg_val = &cntx->fp.f.f[reg_num]; 405 - else 406 - return -EINVAL; 407 - } else if ((rtype == KVM_REG_RISCV_FP_D) && 408 - riscv_isa_extension_available(&isa, d)) { 409 - if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) { 410 - if (KVM_REG_SIZE(reg->id) != sizeof(u32)) 411 - return -EINVAL; 412 - reg_val = &cntx->fp.d.fcsr; 413 - } else if ((KVM_REG_RISCV_FP_D_REG(f[0]) <= reg_num) && 414 - reg_num <= KVM_REG_RISCV_FP_D_REG(f[31])) { 415 - if (KVM_REG_SIZE(reg->id) != sizeof(u64)) 416 - return -EINVAL; 417 - reg_val = &cntx->fp.d.f[reg_num]; 418 - } else 419 - return -EINVAL; 420 - } else 421 - return -EINVAL; 422 - 423 - if (copy_from_user(reg_val, uaddr, KVM_REG_SIZE(reg->id))) 424 - return -EFAULT; 425 413 426 414 return 0; 427 415 }
+167
arch/riscv/kvm/vcpu_fp.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright (C) 2021 Western Digital Corporation or its affiliates. 4 + * 5 + * Authors: 6 + * Atish Patra <atish.patra@wdc.com> 7 + * Anup Patel <anup.patel@wdc.com> 8 + */ 9 + 10 + #include <linux/errno.h> 11 + #include <linux/err.h> 12 + #include <linux/kvm_host.h> 13 + #include <linux/uaccess.h> 14 + 15 + #ifdef CONFIG_FPU 16 + void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu) 17 + { 18 + unsigned long isa = vcpu->arch.isa; 19 + struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; 20 + 21 + cntx->sstatus &= ~SR_FS; 22 + if (riscv_isa_extension_available(&isa, f) || 23 + riscv_isa_extension_available(&isa, d)) 24 + cntx->sstatus |= SR_FS_INITIAL; 25 + else 26 + cntx->sstatus |= SR_FS_OFF; 27 + } 28 + 29 + void kvm_riscv_vcpu_fp_clean(struct kvm_cpu_context *cntx) 30 + { 31 + cntx->sstatus &= ~SR_FS; 32 + cntx->sstatus |= SR_FS_CLEAN; 33 + } 34 + 35 + void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx, 36 + unsigned long isa) 37 + { 38 + if ((cntx->sstatus & SR_FS) == SR_FS_DIRTY) { 39 + if (riscv_isa_extension_available(&isa, d)) 40 + __kvm_riscv_fp_d_save(cntx); 41 + else if (riscv_isa_extension_available(&isa, f)) 42 + __kvm_riscv_fp_f_save(cntx); 43 + kvm_riscv_vcpu_fp_clean(cntx); 44 + } 45 + } 46 + 47 + void kvm_riscv_vcpu_guest_fp_restore(struct kvm_cpu_context *cntx, 48 + unsigned long isa) 49 + { 50 + if ((cntx->sstatus & SR_FS) != SR_FS_OFF) { 51 + if (riscv_isa_extension_available(&isa, d)) 52 + __kvm_riscv_fp_d_restore(cntx); 53 + else if (riscv_isa_extension_available(&isa, f)) 54 + __kvm_riscv_fp_f_restore(cntx); 55 + kvm_riscv_vcpu_fp_clean(cntx); 56 + } 57 + } 58 + 59 + void kvm_riscv_vcpu_host_fp_save(struct kvm_cpu_context *cntx) 60 + { 61 + /* No need to check host sstatus as it can be modified outside */ 62 + if (riscv_isa_extension_available(NULL, d)) 63 + __kvm_riscv_fp_d_save(cntx); 64 + else if (riscv_isa_extension_available(NULL, f)) 65 + __kvm_riscv_fp_f_save(cntx); 66 + } 67 + 68 + void kvm_riscv_vcpu_host_fp_restore(struct kvm_cpu_context *cntx) 69 + { 70 + if (riscv_isa_extension_available(NULL, d)) 71 + __kvm_riscv_fp_d_restore(cntx); 72 + else if (riscv_isa_extension_available(NULL, f)) 73 + __kvm_riscv_fp_f_restore(cntx); 74 + } 75 + #endif 76 + 77 + int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu, 78 + const struct kvm_one_reg *reg, 79 + unsigned long rtype) 80 + { 81 + struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; 82 + unsigned long isa = vcpu->arch.isa; 83 + unsigned long __user *uaddr = 84 + (unsigned long __user *)(unsigned long)reg->addr; 85 + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | 86 + KVM_REG_SIZE_MASK | 87 + rtype); 88 + void *reg_val; 89 + 90 + if ((rtype == KVM_REG_RISCV_FP_F) && 91 + riscv_isa_extension_available(&isa, f)) { 92 + if (KVM_REG_SIZE(reg->id) != sizeof(u32)) 93 + return -EINVAL; 94 + if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr)) 95 + reg_val = &cntx->fp.f.fcsr; 96 + else if ((KVM_REG_RISCV_FP_F_REG(f[0]) <= reg_num) && 97 + reg_num <= KVM_REG_RISCV_FP_F_REG(f[31])) 98 + reg_val = &cntx->fp.f.f[reg_num]; 99 + else 100 + return -EINVAL; 101 + } else if ((rtype == KVM_REG_RISCV_FP_D) && 102 + riscv_isa_extension_available(&isa, d)) { 103 + if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) { 104 + if (KVM_REG_SIZE(reg->id) != sizeof(u32)) 105 + return -EINVAL; 106 + reg_val = &cntx->fp.d.fcsr; 107 + } else if ((KVM_REG_RISCV_FP_D_REG(f[0]) <= reg_num) && 108 + reg_num <= KVM_REG_RISCV_FP_D_REG(f[31])) { 109 + if (KVM_REG_SIZE(reg->id) != sizeof(u64)) 110 + return -EINVAL; 111 + reg_val = &cntx->fp.d.f[reg_num]; 112 + } else 113 + return -EINVAL; 114 + } else 115 + return -EINVAL; 116 + 117 + if (copy_to_user(uaddr, reg_val, KVM_REG_SIZE(reg->id))) 118 + return -EFAULT; 119 + 120 + return 0; 121 + } 122 + 123 + int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu, 124 + const struct kvm_one_reg *reg, 125 + unsigned long rtype) 126 + { 127 + struct kvm_cpu_context *cntx = &vcpu->arch.guest_context; 128 + unsigned long isa = vcpu->arch.isa; 129 + unsigned long __user *uaddr = 130 + (unsigned long __user *)(unsigned long)reg->addr; 131 + unsigned long reg_num = reg->id & ~(KVM_REG_ARCH_MASK | 132 + KVM_REG_SIZE_MASK | 133 + rtype); 134 + void *reg_val; 135 + 136 + if ((rtype == KVM_REG_RISCV_FP_F) && 137 + riscv_isa_extension_available(&isa, f)) { 138 + if (KVM_REG_SIZE(reg->id) != sizeof(u32)) 139 + return -EINVAL; 140 + if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr)) 141 + reg_val = &cntx->fp.f.fcsr; 142 + else if ((KVM_REG_RISCV_FP_F_REG(f[0]) <= reg_num) && 143 + reg_num <= KVM_REG_RISCV_FP_F_REG(f[31])) 144 + reg_val = &cntx->fp.f.f[reg_num]; 145 + else 146 + return -EINVAL; 147 + } else if ((rtype == KVM_REG_RISCV_FP_D) && 148 + riscv_isa_extension_available(&isa, d)) { 149 + if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) { 150 + if (KVM_REG_SIZE(reg->id) != sizeof(u32)) 151 + return -EINVAL; 152 + reg_val = &cntx->fp.d.fcsr; 153 + } else if ((KVM_REG_RISCV_FP_D_REG(f[0]) <= reg_num) && 154 + reg_num <= KVM_REG_RISCV_FP_D_REG(f[31])) { 155 + if (KVM_REG_SIZE(reg->id) != sizeof(u64)) 156 + return -EINVAL; 157 + reg_val = &cntx->fp.d.f[reg_num]; 158 + } else 159 + return -EINVAL; 160 + } else 161 + return -EINVAL; 162 + 163 + if (copy_from_user(reg_val, uaddr, KVM_REG_SIZE(reg->id))) 164 + return -EFAULT; 165 + 166 + return 0; 167 + }