mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
RISC-V: KVM: Add support for SBI STA registers
KVM userspace needs to be able to save and restore the steal-time shared memory address. Provide the address through the get/set-one-reg interface with two ulong-sized SBI STA extension registers (lo and hi). 64-bit KVM userspace must not set the hi register to anything other than zero and is allowed to completely neglect saving/restoring it. Reviewed-by: Anup Patel <anup@brainfault.org> Signed-off-by: Andrew Jones <ajones@ventanamicro.com> Signed-off-by: Anup Patel <anup@brainfault.org>
This commit is contained in:
parent
5b9e41321b
commit
f61ce890b1
@ -70,6 +70,11 @@ bool riscv_vcpu_supports_sbi_ext(struct kvm_vcpu *vcpu, int idx);
|
||||
int kvm_riscv_vcpu_sbi_ecall(struct kvm_vcpu *vcpu, struct kvm_run *run);
|
||||
void kvm_riscv_vcpu_sbi_init(struct kvm_vcpu *vcpu);
|
||||
|
||||
int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num,
|
||||
unsigned long *reg_val);
|
||||
int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu, unsigned long reg_num,
|
||||
unsigned long reg_val);
|
||||
|
||||
#ifdef CONFIG_RISCV_SBI_V01
|
||||
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_v01;
|
||||
#endif
|
||||
|
@ -161,6 +161,12 @@ enum KVM_RISCV_SBI_EXT_ID {
|
||||
KVM_RISCV_SBI_EXT_MAX,
|
||||
};
|
||||
|
||||
/* SBI STA extension registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
|
||||
struct kvm_riscv_sbi_sta {
|
||||
unsigned long shmem_lo;
|
||||
unsigned long shmem_hi;
|
||||
};
|
||||
|
||||
/* Possible states for kvm_riscv_timer */
|
||||
#define KVM_RISCV_TIMER_STATE_OFF 0
|
||||
#define KVM_RISCV_TIMER_STATE_ON 1
|
||||
@ -244,6 +250,9 @@ enum KVM_RISCV_SBI_EXT_ID {
|
||||
|
||||
/* Registers for specific SBI extensions are mapped as type 10 */
|
||||
#define KVM_REG_RISCV_SBI_STATE (0x0a << KVM_REG_RISCV_TYPE_SHIFT)
|
||||
#define KVM_REG_RISCV_SBI_STA (0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT)
|
||||
#define KVM_REG_RISCV_SBI_STA_REG(name) \
|
||||
(offsetof(struct kvm_riscv_sbi_sta, name) / sizeof(unsigned long))
|
||||
|
||||
/* Device Control API: RISC-V AIA */
|
||||
#define KVM_DEV_RISCV_APLIC_ALIGN 0x1000
|
||||
|
@ -961,18 +961,19 @@ static unsigned long num_sbi_ext_regs(struct kvm_vcpu *vcpu)
|
||||
return copy_sbi_ext_reg_indices(vcpu, NULL);
|
||||
}
|
||||
|
||||
static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int copy_sbi_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
||||
{
|
||||
int n = num_sbi_regs(vcpu);
|
||||
struct kvm_vcpu_sbi_context *scontext = &vcpu->arch.sbi_context;
|
||||
int total = 0;
|
||||
|
||||
if (scontext->ext_status[KVM_RISCV_SBI_EXT_STA] == KVM_RISCV_SBI_EXT_STATUS_ENABLED) {
|
||||
u64 size = IS_ENABLED(CONFIG_32BIT) ? KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
|
||||
int n = sizeof(struct kvm_riscv_sbi_sta) / sizeof(unsigned long);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
u64 reg = KVM_REG_RISCV | KVM_REG_SIZE_U64 |
|
||||
KVM_REG_RISCV_SBI_STATE | i;
|
||||
u64 reg = KVM_REG_RISCV | size |
|
||||
KVM_REG_RISCV_SBI_STATE |
|
||||
KVM_REG_RISCV_SBI_STA | i;
|
||||
|
||||
if (uindices) {
|
||||
if (put_user(reg, uindices))
|
||||
@ -981,7 +982,15 @@ static int copy_sbi_reg_indices(struct kvm_vcpu *vcpu, u64 __user *uindices)
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
total += n;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu)
|
||||
{
|
||||
return copy_sbi_reg_indices(vcpu, NULL);
|
||||
}
|
||||
|
||||
static inline unsigned long num_vector_regs(const struct kvm_vcpu *vcpu)
|
||||
|
@ -345,6 +345,8 @@ int kvm_riscv_vcpu_set_reg_sbi(struct kvm_vcpu *vcpu,
|
||||
reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
|
||||
|
||||
switch (reg_subtype) {
|
||||
case KVM_REG_RISCV_SBI_STA:
|
||||
return kvm_riscv_vcpu_set_reg_sbi_sta(vcpu, reg_num, reg_val);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -370,6 +372,9 @@ int kvm_riscv_vcpu_get_reg_sbi(struct kvm_vcpu *vcpu,
|
||||
reg_num &= ~KVM_REG_RISCV_SUBTYPE_MASK;
|
||||
|
||||
switch (reg_subtype) {
|
||||
case KVM_REG_RISCV_SBI_STA:
|
||||
ret = kvm_riscv_vcpu_get_reg_sbi_sta(vcpu, reg_num, ®_val);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
* Copyright (c) 2023 Ventana Micro Systems Inc.
|
||||
*/
|
||||
|
||||
#include <linux/kconfig.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kvm_host.h>
|
||||
|
||||
#include <asm/kvm_vcpu_sbi.h>
|
||||
@ -59,3 +61,56 @@ const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta = {
|
||||
.handler = kvm_sbi_ext_sta_handler,
|
||||
.probe = kvm_sbi_ext_sta_probe,
|
||||
};
|
||||
|
||||
int kvm_riscv_vcpu_get_reg_sbi_sta(struct kvm_vcpu *vcpu,
|
||||
unsigned long reg_num,
|
||||
unsigned long *reg_val)
|
||||
{
|
||||
switch (reg_num) {
|
||||
case KVM_REG_RISCV_SBI_STA_REG(shmem_lo):
|
||||
*reg_val = (unsigned long)vcpu->arch.sta.shmem;
|
||||
break;
|
||||
case KVM_REG_RISCV_SBI_STA_REG(shmem_hi):
|
||||
if (IS_ENABLED(CONFIG_32BIT))
|
||||
*reg_val = upper_32_bits(vcpu->arch.sta.shmem);
|
||||
else
|
||||
*reg_val = 0;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int kvm_riscv_vcpu_set_reg_sbi_sta(struct kvm_vcpu *vcpu,
|
||||
unsigned long reg_num,
|
||||
unsigned long reg_val)
|
||||
{
|
||||
switch (reg_num) {
|
||||
case KVM_REG_RISCV_SBI_STA_REG(shmem_lo):
|
||||
if (IS_ENABLED(CONFIG_32BIT)) {
|
||||
gpa_t hi = upper_32_bits(vcpu->arch.sta.shmem);
|
||||
|
||||
vcpu->arch.sta.shmem = reg_val;
|
||||
vcpu->arch.sta.shmem |= hi << 32;
|
||||
} else {
|
||||
vcpu->arch.sta.shmem = reg_val;
|
||||
}
|
||||
break;
|
||||
case KVM_REG_RISCV_SBI_STA_REG(shmem_hi):
|
||||
if (IS_ENABLED(CONFIG_32BIT)) {
|
||||
gpa_t lo = lower_32_bits(vcpu->arch.sta.shmem);
|
||||
|
||||
vcpu->arch.sta.shmem = ((gpa_t)reg_val << 32);
|
||||
vcpu->arch.sta.shmem |= lo;
|
||||
} else if (reg_val != 0) {
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user